• Post Reply Bookmark Topic Watch Topic
  • New Topic

super class question  RSS feed

 
Dan Bromberg
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
I have a followup question regarding the code [see below] I posted a few days ago:
QUESTION: The comment line with the '!'s shows reference 'x' pointing to reference 'y'. Since "Y" is a subclass of "X", does this force reference 'x' to point to the super class of 'y'?
I'm unclear since there is no 'new' operator for reference 'x' so that means 'x' is not pointing to an X class. But by equating x to y it seems to me that imposes a relationship even though there is no class for 'x' to point to. So by creating 'y' with 'new' I assume y's constructor will call the superclass constructor, which reference 'x' will point to. Is that correct? Is there a nice way to test this?

Thanks in advance,
Dan

Here's the code:
===============
class X { public String toString() { return "I am an X."; } }
class Y extends X { public String toString() { return "I am a Y."; } }

public class Ex0304
{ public static void main(String[] args)
{ Y y = new Y();
System.out.println("y: " + y);
X x = y; //!!!
System.out.println("x: " + x);
Y yy = (Y)x; // casts x as type Y
System.out.println("yy: " + yy);
X xx = new X();
System.out.println("xx: " + xx);
yy = (Y)xx; // RUN-TIME ERROR: xx cannot be cast as a Y
System.out.println("yy: " + yy);
}
}
[ October 19, 2005: Message edited by: Dan Bromberg ]
 
Andyjr Robinson
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Dan.
You need to visualise what gets created on the heap and what types of pointers are in use.The terms UpCasting and Downcasting have been used in a previous response so I'll stick to them.

UpCasting is always fine. Y y = new Y() creates an object of type Y on the heap with a pointer of type Y. You can always then use X x = y (a cast to X is optional and doesn't affect it). When complete we have an object of type Y that has two pointers pointing to it - one of type Y and another of type X.

DownCasting comes in 2 flavours and can result in Runtime errors depending upon what object is on the heap.

1. X x = new Y() creates an object of type Y on the heap with a pointer of type X pointing to it. Because the object is of type Y, it is fine to set another pointer, this time type Y, to it by using Y y = (Y)x. The cast is mandatory but will be fine and error free.

2. X x = new X() creates an object of type X on the heap with a pointer of type X. If you then want to make another pointer of type Y to that object then this can be done using Y y = (Y)x (as above). The cast is mandatory and although correct as far as syntax is concerned (i.e it will compile) it will cause a runtime error


Hope this clarifies it a little ??
 
Joel McNary
Bartender
Posts: 1840
Eclipse IDE Java Ruby
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
So by creating 'y' with 'new' I assume y's constructor will call the superclass constructor, which reference 'x' will point to. Is that correct?
Yes--but not like you're thinking. The 'x' constructor is constructing the same object as the 'y' constructor, so reference 'x' will point to the object created by the 'x' constructor, but also to the object created by the 'y' constructor, because they're the same object.

You've stumbled onto the wonderful topic of abstraction and polymoprhism.
To make things a little clearer by way of conctere explanation:

Assume that we have class Dog, class Coelecanth, and class Platypus. Dog is a subclass of the class Mammal; Coelecanth is a subclass of the class Fish, and Platypus is a subclass of the class Monotreme (which is a subclass of Mammal). Both Mammal and Fish are subclasses of the class Animal.

Now, you can write code like:


and that's fine -- dogs can bark. You can't say:

becuase the aDog variable is referencing an Animal, and not all Animals bark (Coelecanths and Platypuses (Platypii?) cannot).

But say you wrote:


Note that Dog, Coelecanth, and Platypus are all Animals, so the cast on line 17 is always valid. However, since the reference type is animal, we can only call methods that Animals can perform. reproduce() is one such method; note that different subclasses implement this method different ways. (Mammals, like Dogs, give birth to live young. Fish lay eggs. Monotremes override the Mammal's method so that they lay eggs as well as fish.)

This ability is called polymorphism (see How my Dog learned Polymorphism for another story on polymorphism). The Animal reference doen't point to the superclass of the object -- it points to the object itself. There is no separate superclass object created. Instead, it lets you refer to a generic Animal and work with it as an animal.
[ October 20, 2005: Message edited by: Joel McNary ]
 
Layne Lund
Ranch Hand
Posts: 3061
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
First, reference variables don't point to classes; they point to objects. Both x and y are "pointing" to the same object which has type Y. However, since the type of x is X, then you can only access the methods available in X. This should make sense because a Y "is a" X. This is the common test to use to tell when you can make an assignment without an explicit cast.

For example, a Dog "is an" Animal. So if we uses classes to model different kinds of animals, you can think of the reference variables as a leash. We might have a general "animal leash" that can be used on any kind of animal or a specific "dog leash" that can only be used on dogs (because it has a muzzle, for example). Say we also have a Cat class. We can use an "animal leash" on either a Cat or a Dog. The type of the animal at the end of the leash doesn't change just because we are using the generic animal leash.

I hope this analogy makes some sense. Feel free to come back with more questions.

Layne
[ October 21, 2005: Message edited by: Layne Lund ]
 
Dan Bromberg
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Andyjr,
Joel,
Layne:

Could you be more precise why a runtime error occurs? ie, what basic rule of Java is being violated at runtime? The compiler apparently is satisfied but the runtime system is not: how come? I realize an improper cast is being done which the compiler thinks is fine but what does the runtime system see that the compiler does not?

More generally, where in the SUN documentation for JAVA should I be looking to understand why there will be an exception thrown?

I very much appreciate your time and have already learnt from your efforts.

Dan
 
Layne Lund
Ranch Hand
Posts: 3061
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You might look at the API docs for ClassCastException since this is the exception that is thrown. You can also use the "is a" test that I referred to earlier. In this case, xx points to an object of type X. So you should ask, "Is an X also a Y?" The answer is no, because X does not extend Y. The inheritence relationship is the other way around (i.e. a Y is an X). This means that you cannot cast an X object to a Y object. The cast only works if the original object really is a Y, even if you are using a reference of type X to refer to it.

I hope this helps.

Layne
[ October 21, 2005: Message edited by: Layne Lund ]
 
Dan Bromberg
Ranch Hand
Posts: 52
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Layne,

Your last explanation regarding my cast question cleard up the issue for me. I didn't realize that the superclass reference must actually point/refer to the subclass reference prior to performing the cast [even though the earlier part of the example suggested it]. I thought it was enough for the superclass/subclass relation to exist.

Thanks very much for your time,
Dan
 
Layne Lund
Ranch Hand
Posts: 3061
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Just a point about terminology: references cannot and do not point to other references. Instead, references point to objects. This means that it is more correct to say "the superclass reference must actually point/refer to a subclass object prior to performing the cast".

Layne
[ October 22, 2005: Message edited by: Layne Lund ]
 
It is sorta covered in the JavaRanch Style Guide.
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!