Hey everyone~! I am having a major issue understanding class casting. I thought I understood it, but I found 2 problems in my Barron's book that seem to contradict in their explanations. Can someone please explain the distinction between these two problems???

Problem 1:

Bird = Super class
Owl = Subclass of Bird
Parrot = Subclass of Bird
Parakeet = Subclass of Parrot

public class BirdStuff
{
    public static void printName(Bird b)
    { /* Implementation Not Shown */}

    public static void printBirdCall(Parrot p)
    { /* Implementation Not Shown */}

    public static void main(String[] args)
    {
        Bird bird = new Parrot();
        printName(bird);
        printBirdCall(bird);
    }
}

The code above causes an error because even though bird takes a Parrot object, it is treated like a bird and thus cannot be used in the printBirdCall() method without first being cast down to a Parrot using the syntax printBirdCall((Parrot) bird).


Problem 2:

Consider these declarations:

Integer intOb = new Integer(3);
Object ob = new Integer(4);
Double doubOb = new Double(3.0);
if (intOb.compareTo(ob)<0)...

The code above does not cause an error, because ob contains an Integer object, so when intOb calls its compareTo() method that accepts an Integer parameter, this will work correctly.


My confusion: Isn't one of them wrong??? If intOb calls compareTo() correctly on ob which is of type object, shouldn't the printBirdCall() be called correctly on bird, since it is an instance of Parrot? Is there a distinction to be made between these 2 cases??? Help!!!

My confusion: Isn't one of them wrong??? If intOb calls compareTo() correctly on ob which is of type object, shouldn't the printBirdCall() be called correctly on bird, since it is an instance of Parrot? Is there a distinction to be made between these 2 cases??? Help!!!

The Object class has a compareTo method on it. That is why it works. However I am guessing your Bird class does not have a printBirdCall in it like it should. It is only located in your Parrot class.

My confusion: Isn't one of them wrong??? If intOb calls compareTo() correctly on ob which is of type object, shouldn't the printBirdCall() be called correctly on bird, since it is an instance of Parrot? Is there a distinction to be made between these 2 cases??? Help!!!

No. Look at the method declarations. printBirdCall() is declared as taking one argument of type Parrot. You passed it a Bird, and it does not know that the type of Bird was a Parrot. However, the Integer class has a compareTo method that takes an Object as its argument. You passed it an Object. It was happy, and then underneath the covers, it probably did something like

if (objectYouPassedIt instanceof Integer){
Integer anInt = (Integer)objectYouPassedIt;
}

The Object class has a compareTo method on it. That is why it works. However I am guessing your Bird class does not have a printBirdCall in it like it should. It is only located in your Parrot class.

All of that is wrong. The Object class has no such method. The compareTo method is from the Comparable interface. And even if his Bird class did have a printBirdCall method, it wouldn't matter. If you notice, he posted the following:

public class BirdStuff
{

    public static void printBirdCall(Parrot p)
    { /* Implementation Not Shown */}

    public static void main(String[] args)
    {
        Bird bird = new Parrot();
        printBirdCall(bird);
    }
}

He called a static method of the class BirdStuff and passed in a Bird, he did not call a method of the Bird class or of the Parrot class. So it doesn't matter what classes contain the "printBirdCall" method.

Anyway, to the OP: consider that if you change the method to the following, it will work.

public static void printBirdCall(Bird p)

Consider the reason why this makes sense. Since Bird is the superclass, and Parrot is a subclass, that means that a Parrot has all of the things that a Bird has... and more. So if the compiler let you pass in a Bird where a Parrot was required (by the method declaration), it would not make any sense. For example, lets say the classes contain the following things:

public class Bird{
int squawk;
}
public class Parrot extends Bird{
//squawk is inherited from Bird
String makeNoise;
}

Now, if a method says that it wants you to pass in a Parrot, but you pass in a Bird. . what happens when you say bird.makeNoise? Since Bird doesn't have a makeNoise variable, you run into all sorts of trouble. The opposite does not hold, since if a method says you need to pass in a Bird, but you pass in a Parrot, a Parrot is a Bird (it has all of the methods that a Bird has, and all of the instance variables that Bird has). So you can run into problems the one way, but not the other.

Consider these declarations:

Integer intOb = new Integer(3);
Object ob = new Integer(4);
Double doubOb = new Double(3.0);
if (intOb.compareTo(ob)<0)...

I tried this and get the following error:
The method compareTo(Integer) in the type Integer is not applicable for the arguments (Object)

Perhaps I am using a different version of java than you (which I really don't think matters in this case). Maybe I am just missing something obvious.

All of that is wrong. The Object class has no such method. The compareTo method is from the Comparable interface. And even if his Bird class did have a printBirdCall method, it wouldn't matter. If you notice, he posted the following:

That was the problem...I read it too quickly. Sorry about that you are totally right.

I tried this and get the following error:
The method compareTo(Integer) in the type Integer is not applicable for the arguments (Object)

Perhaps I am using a different version of java than you (which I really don't think matters in this case). Maybe I am just missing something obvious.

Actually, my apologies, that doesn't work for me either. Which means that the method which I listed earlier does not actually exist in the Integer class.

So does the public static void printBirdCall(Parrot p) with bird passed work? Or is it that the integer comparison does not work? Unless there is a clear distinction between the 2 cases, it seems to me that Barron's contradicts itself in saying that the printBirdCall thing will result in an error but that the integer comparison will work.

So does the public static void printBirdCall(Parrot p) with bird passed work? Or is it that the integer comparison does not work? Unless there is a clear distinction between the 2 cases, it seems to me that Barron's contradicts itself in saying that the printBirdCall thing will result in an error but that the integer comparison will work.

There is a clear distinction. Whether or not the line of code works depends on whether or not the corresponding method exists and it also depends on the inheritance hierarchy. In the case of passing a Bird Object to a method declared as accepting a Parrot, it will not work, because a Bird does not necessarily have all of the characteristics that a Parrot has (see my earlier example). However, if the same method was declared as accepting a Bird Object, and you said Parrot parrot = new Parrot(), you would still be able to pass it "parrot" and it would work.

The Integer compareTo method follows the same rules. The author's example only worked because the method he was calling was declared as accepting an Object as its argument. Since an Integer is an Object, it should be allowed to be passed in.

The Integer compareTo method follows the same rules. The author's example only worked because the method he was calling was declared as accepting an Object as its argument. Since an Integer is an Object, it should be allowed to be passed in.

But in the Integer class in the Java API, the method compareTo() accepts an Integer, not an Object. So isn't that like accepting a Parrot instead of a Bird? Even though the comparable interface specifies compareTo() as accepting type Object, the Integer class uses "public int compareTo(Integer anotherInteger)".

But in the Integer class in the Java API, the method compareTo() accepts an Integer, not an Object. So isn't that like accepting a Parrot instead of a Bird? Even though the comparable interface specifies compareTo() as accepting type Object, the Integer class uses "public int compareTo(Integer anotherInteger)".

You're right. Except that when the author of your book wrote his piece of code, I'm guessing at that time, the compareTo method was listed as the one found here, which takes an Object. . not an Integer. So your book's author is not really wrong, just out of date. What you're saying is correct.

K got it :D

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.