user2911290 user2911290 - 1 month ago 8
Java Question

Confused about traversing a class hierarchy with polymorphism

Say I have a superclass called Fish, and a subclass called Tuna. I don't understand why this works:

Fish f;
Tuna t = new Tuna();

f=t; // I am confused about this statement
f.swim(); // (Tuna's swim method is invoked)


Why is the fish variable allowed to "become involved with" (for want of a better phrase) the more specialized Tuna object? The way that my obviously erroneous "noob OOP Java brain" works is:

Tuna "is a" Fish is OK. Fish "is a" Tuna isn't OK. Therefore f=t shouldn't be OK, and t=f should be OK. But from my example above, the opposite is true!

Thanks very much for any help on this. I apologize in advance for my ignorance, as I have only just begun to learn Java.

Edit. Thanks a lot for all replies below. From them, I now understand that:

The variable called f is of type Fish, and as such, is allowed to contain the data value (object reference) located inside the variable called t, as t refers to a Tuna object, and is therefore of a compatible type for f to use. It's compatible because a tuna is a fish.

Answer

The value of the f variable is a reference. That can be a null reference, or a reference to any object which "is a fish". As a Tuna object is a Fish object, it's fine to copy the value from t, which must either be a null reference or a reference to a Tuna object.

Assignment just copied the value of the expression on the right hand side to the variable on the left hand side. That's all it does.

To put it another way: anything you can do to a Fish, you can do to a Tuna. So there's no value of t such that:

f = t;
f.swim();

is nonsensical. (t could be a null reference of course, but that's not seen as a problem in the type system as such.) There will always be an appropriate swim method to call, so long as t is non-null.

Compare that with a different type. If we had:

String s = "foo";
f = s;
f.swim();

then that wouldn't make sense, because you can't ask a String to swim.

The type safety rules ensure that you can never try to call a method (or access a field) and find that you're using a type for which that method/field simply doesn't exist. The fact that Tuna extends Fish means that anything you can do with a "general" fish, you can do with a tuna too.