Matt Dexter
Matt Dexter

Reputation: 248

Basic polymorphism in Java/casting a superclass as a subclass

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();
            }
        }
    }
}

Upvotes: 0

Views: 660

Answers (4)

Vihar
Vihar

Reputation: 3831

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!

Upvotes: 1

Brian Roach
Brian Roach

Reputation: 76918

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.

Upvotes: 2

Tanmay Patil
Tanmay Patil

Reputation: 7057

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.

Upvotes: 2

Christian Tapia
Christian Tapia

Reputation: 34186

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.

Upvotes: 2

Related Questions