my dog learned polymorphism*
The moose likes Beginning Java and the fly likes OOP? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login

Win a copy of Murach's Java Servlets and JSP this week in the Servlets forum!
JavaRanch » Java Forums » Java » Beginning Java
Bookmark "OOP?" Watch "OOP?" New topic


Frankie Chee
Ranch Hand

Joined: Oct 26, 2003
Posts: 43

Just went through the camp fire stories, correct me if I am wrong. This is what I think happened in the above example:
1)In 'a.callme()' the JVM refer to class A to look for the 'callme' because 'A a=new B()' declares 'a' with reference to class A but the object was created by class B's constructor.
2)Based on the code 'new B()'. The JVM decides that the "REAL" object comes from class B and calls the 'callme()'method in class B, even though there is a similar method in class A.
3)However, during compilation, the compiler have to check for the 'callme()' method in class A for without it there will be a compilation error; although the object itself is created by class B's constructor?
grrrr really confused hope I am getting close to the truth.
Davy Kelly
Ranch Hand

Joined: Jan 12, 2004
Posts: 384
I think what your trying to discover is polymorphism.
yes if you have a class super{} and class sub extend super{}
then if you make an object like super sup = new Sub() you will have a sub object with a super reference.
this is what happens:

plus you can test it yourself, code it in a program, then take away the callme() from A and see what heppens??? because you have a reference to A and an object of B: B extends A
hope this helps you see what happened.
[ March 02, 2004: Message edited by: Davy Kelly ]

How simple does it have to be???
Frankie Chee
Ranch Hand

Joined: Oct 26, 2003
Posts: 43
Hi there,
thank you, I think I got the idea right now!!!
Really tough studying night classes, the teacher tired so are the students after working for the previous 9 hours.
Davy Kelly
Ranch Hand

Joined: Jan 12, 2004
Posts: 384
hey Frankie,
I know how it feels, I did java while working full time, so could only study in my spare time.
it will all click in to place one day, but keep up the good work. and keep posting here, we will help out and point you in the right direction.
sever oon
Ranch Hand

Joined: Feb 08, 2004
Posts: 268
Your example shows a case of variable shadowing, which is allowed by the language but never a good idea. The int r is defined as a class level variable in both class A and B, and there's never a good reason to do this if B extends A. If those two variables represent the same data, then B should just use the variable it inherits from A. A should provide an accessor and mutator (getter/setter) that B should use instead of keeping another copy around.
If r represents different data altogether in B, then B should give it a different name. The name of any piece of data in a system should specifically describe that data well enough to disambiguate it from other data in the same class. When B extends A, it inherits all of A's data members, meaning that A's data members are now also part of B, just like A's methods are inherited by B. So B has an int r that it defines, and another int r that it inherits from A. This is of course not ambiguous to the compiler, but it will create doubt in the minds of programmers everywhere and is therefore to be avoided.
As far as polymorphism goes, here's a key concept every Java programmer should understand: the difference between type and class.
These terms are often used interchangably (most of the time this doesn't change the meaning of correctness of the statement, but sometimes it does). The "class" of an object is not quite the same as the "type" of an object. The distinction is: when an object is born, it is born of a specific, instantiable class. That object is of that class from the moment it's newed up to the time it is garbage collected. Objects cannot change their class.
The "type" of a class, however, is conferred upon that object by the reference that is used to access it. See the example code below for clarity:

In the code above, what is happening on line 1? I create a new LinkedList object on the heap, and assign the reference to that object to a variable called link. The new operator does more than one thing here: (1) declares memory on the heap for a LinkedList object, (2) creates the object and places it in that memory, (3) initializes the object by running its chain of constructors, and (4) returns a reference to that object. The = operator assigns the returned value of the new operator to link.
Now, as I was saying, because the new operator created a LinkedList, the reference stored in link refers to an object of class LinkedList. LinkedList is now and forever the class to which this object belongs.
On line 1, I am referring to that object with a variable of *type* LinkedList. That means, whenever I call a method on the object referred to by that particular reference, the JVM will treat the object as type LinkedList.
On line 2, I assign the reference to a new variable, list, of type List. Now, the object that list refers to is still of class LinkedList, but if I use the list reference to access that object, then it is of type List. Similarly, on line 3, I create a new reference called obj that allows me to treat the object of class LinkedList as type Object.
So now I have 3 different references to this object of class LinkedList, allowing me to treat it as type Object, List, or LinkedList. So while class is a long-lived concept, type only lives for the duration of a method call. The type is conferred upon the object for the duration of that method call depending on which reference I use:

In this code, it is important to realize that the hashCode() method that runs in all cases is the implementation attached to the object on the heap. The method implementation that runs will never change--the implementations are determined by the class of an object, not by its type. Consider the following:

In the above code, it is impossible for AbstractShape to calculate the perimeter of a shape because it's not a particular kind of shape, and each kind of shape uses a different formula for calculating its perimeter. (Normally, of course, AbstractShape would be declared abstract and just leave the method in the Shape interface abstract and not define it at all, but for the purposes of this example I've given that method a default implementation and made the class concrete to illustrate the point.)
So, consider the following:

In this code, there are only two objects created, an object of class Circle and another of class Square. There are three different ways of referencing each of those objects:

All three of these calls to getPerimeter() is calling the same exact implementation of that method--the one attached to Circle. Why? Because the referent object in each case is of *class* Circle, regardless of the fact that different types are being conferred upon that object in each call. So this code will never print out -1. Indeed, if you look at that last call, you'll see that method implementations must be determined by the class of an object and not its type; in that call we're referencing the object as a Shape, which is an interface and therefore can not have implementations defined.
Now let's see why it's unnecessary to use variable shadowing. Consider this rewrite of the above shape example:

I could have implemented Circle and Square so that they declared a class variable numSides and set it. But why? They extend AbstractShape, which already declares this variable, and that means they inherit it as well. It's a private variable, so they cannot access it, but it's important to realize that in the above code, Circle *already has* a numSides variable. Declaring another one with the same name is exactly equivalent to declaring another int with a different name, like nSides, and using it instead of numSides. This would leave numSides lying dormant, certainly a waste of memory and a bad design (because now there's ambiguity as to where this data *should* be stored--there are two places, numSides and nSides, equally valid according to this design).
When a class extends another class, it literally gets that data as though it declared it--newing up a Circle object will now declare space inside that object's memory to hold this int. And it can access it using the getter and setter provided by the AbstractShape class, which are also inherited by the Circle object and therefore attached to it.
Just for the sake of completeness, I will show the shape code the way I would actually implement it. You can look at the differences between it and the other versions and compare them based on what you have (hopefully) learned.

Eddie Vanda
Ranch Hand

Joined: Mar 18, 2003
Posts: 281
Thanks, Sever, that's the clearest exposition on this subject I have ever read.

The nice thing about Standards is that there are so many to choose from!
I agree. Here's the link:
subject: OOP?
Similar Threads
a doubt with 'extends'
Inheritance problem in Eclipse
Dynamic dispatch
Why no Polymorphism for instance variables
JAVA Upcasting and Downcasting of reference variables