0

I'm working through a Java polymorphism exercise and struggling to understand type conversion & how to call subclass-specific methods. I have a class Dog:

public class Dog { private final String breed; public Dog(String b) { breed = b; } //More Dog methods (bark, eat, etc.) } 

as well as a subclass SledDog, who can pull a sled:

public class SledDog extends Dog { public SledDog(String b) { super(b); } public void pullSled() { System.out.println("pulling the sled"); } } 

In my application, I declare 3 dogs - two regular Dogs and one SledDog. I pass them into an array of Dogs, and I loop through that array. If the dog is a sled dog, I want him to pullSled() - but I can't figure out how to call the method, since it belongs to a subclass. My instructions tell me to cast the array item into a SledDog object, but I can't figure out how, or why it is necessary. I thought that since the object passed to array is already a SledDog, it should have access to pullSled(). Here's my attempt.

public class DogApp { public static void main(String[] args) { Dog firstDog = new Dog("Greyhound"); Dog secondDog = new Dog("Terrier"); SledDog sledDog = new SledDog("Husky"); Dog[] dogArray = new Dog[]{firstDog, secondDog, sledDog}; for(Dog d : dogArray) { //Makes sense, only want to pullSled() if d is a SledDog if(d instanceof SledDog) { // This is the part I'm confused about d = (SledDog) d; d.pullSled(); } } } } 

4 Answers 4

2

You are pretty close, just cast it and call the method:

((SledDog)d).pullSled(); 

inside the if (d instance of SledDog) condition.

Also, I can't see the declaration of dogArray. Be sure you have declared and initialized it correctly.

Sign up to request clarification or add additional context in comments.

2 Comments

So while this works ... it's a bad design. Defining Dog as an abstract class with an abstract pullSled() then overriding pullSled() in the concrete subclasses is generally the preferred way to go about it. At the very least define a pullSlead() in Dog then override it in the subclasses.
This worked! Regarding dogArray - looks like the declaration didn't make it into my example above, I have edited it to include it.
2

There is difference between an object and a reference to an object.

All SledDogs are Dogs but all Dogs are not SledDogs. So according to this logic (as far as compiler understands), following code is fine.

Dog myDog = new SledDog(); // This compiles 

while

SledDog myDog = new Dog(); // Error 

does not work.


So in the first line, the tricky part is that you have an object of SledDog class but you are referring to it by a reference of Dog class. (Since all SledDogs are Dogs, this is perfectly fine)

But while doing this, you are ignoring it's SledDogness. You will be able to access features of SledDog that are inherited from Dog, but SledDog specific features will be unavailable. Remember that object is still a SledDog but you are acknowledging it as a mere Dog.

So in order to access them, you'll have to refer it using a reference of SledDog class. ---> Hence the typecast is required.

SledDog typeCastedMyDog = (SledDog) myDog; 

Now you can access the pullSled() method.


The same logic applies when you put all of them in an array of Dogs.

Hope this helps.

Comments

2

When talking about OOP, trying to discern what the concrete subclass actually is generally means you're doing something wrong.

You could approach this issue by defining a default pullSled() in your Dog class, then overriding it:

public class Dog { private final String breed; public Dog(String b) { breed = b; } public boolean pullSled() { System.out.println("Dude, I'm a " + breed + ", not a Siberian Husky!"); return false; } //More Dog methods (bark, eat, etc.) } public class SledDog extends Dog { public SledDog(String b) { super(b); } @Override public boolean pullSled() { System.out.println("pulling the sled"); return true; } } 

Another option over this simple example, you could also define a field and boolean canPullSled():

public class Dog { private final String breed; protected boolean canPullSled; public Dog(String b) { breed = b; } public boolean canPullSled() { return canPullSled; } public boolean pullSled() { if (canPullSled) { System.out.println("pulling the sled"); return true; } else { System.out.println("Dude, I'm a " + breed + ", not a Siberian Husky!"); return false; } } // other stuff } public class SledDog extends Dog { public SledDog(String b) { super(b); this.canPullSled = true; } } 

Or use a Builder ... or a fluent interface ... or ...

In the end, instanceof is really a last resort, used only when nothing else will do.

Comments

1

If you need a real polymorhic case you can use

superclassName referenceName=subclassObject 

in this way you can access all methods of subclass by use of superclass reference.

Just a hint to get you started,try and take it further good luck!

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.