Reputation: 111
This is an example from "SCJP" by Kathy Sierra: Chapter 2 - Object Orientation
class X { void do1() {} }
class Y extends X { void do2() {} }
class Chrome {
public static void main (String args[]) {
X x1 = new X();
X x2 = new Y(); //***** question is regarding this line
Y y1 = new Y();
((Y)x2).do2();
}
}
Is it legal to create an object using two constructors? And what type of object is x2
: X
or Y
?
Upvotes: 1
Views: 1189
Reputation: 13556
Those are NOT two constructors
X x2 = new Y();
X
is Type of variablex2
is reference variable which can refer to X
and hence any subclass of X
, in this case, it can refer to Y
.new Y()
actually creates the object of class Y
in the memory and the variable x
refer to the object.This is possible because Y
extends X
hence it passes IS-A
test. This is example of polymorphism. A super type is referring to object of subtype.
x2
reference variable will be of type X
x2
will refer to a subclass object i.e. of type Y
.So if there is a method in class X
that is overridden by a method in class Y
, the method of class Y
will get called because the object is of type Y
.
Consider these classes.
public class X {
public void someMethod(){
System.out.println("we are in class X method");
}
}
and another class
public class Y extends X {
public void someMethod(){
System.out.println("we are in class Y method ");
}
public static void main(String [] args){
X x = new X();
X x2 = new Y();
Y y = new Y();
x.someMethod();
x2.someMethod();
y.someMethod();
}
}
This outputs
we are in class X method
we are in class Y method
we are in class Y method
The explanation is :
X x = new X();
creates object of X
with reference of X
so calls someMethod
of class X
.X x2 = new Y();
creates a reference variable of X
but the object of class Y
so the overriding method of class Y
is called because overridden methods have dynamic binding. and which overridden method to call is dependent on the object type.Y y = new Y()
, same explanation as of point 1.Upvotes: 3
Reputation: 241591
x2
has a compile-time type of X
but a runtime type of Y
. What this is means, is that when the compiler needs to reason about x2
it will assume that x2
is an X
. But at runtime, the behavior of x2
will be that of a Y
.
So let's explain this a little more verbosely. This is not legal:
x2.do2();
This is because the compiler thinks that x2
is an X
and X
doesn't have a method named do2
, only Y
does. The compiler doesn't know that x2
is a Y
, it only know the compile-time type of x2
is an X
.
This, however, would be legal, and will not cause a runtime exception:
((Y)x2).do2();
We're telling the compiler, look, I know more than you about x2
; I know that it's a Y
, so just emit instructions that invoke Y.do2
with x2
as the receiver.
Additionally, let's assume we had a method that accepts Y
s:
void M(Y y) { }
Then this would not be legal:
M(x2);
Again, this is because the compiler thinks that x2
is a X
, not all X
s are Y
s, so it has to reject the method invocation.
This, however, would be legal, and will not cause a runtime exception:
M((Y)x2);
Again, we're telling the compiler, look, I know more than you know about x2
; I know that it's a Y
, so just trust me, and invoke that method as if x2
were a Y
.
Let's further assume we have a method defined in X
and overridden in Y
:
class X {
void do1() {}
void N() { System.out.println("X");
}
class Y extends X { void do2() {}
@Override
void N() { System.out.println("Y");
}
Now if we say:
x2.N();
we will see Y
printed to the console. This is because the runtime type of x2
is Y
.
All of this is part of what people mean when they speak of polymorphism.
Is it legal to create an object using two constructors.
There are not two constructors in this statement:
X x2 = new Y();
There is exactly one constructor. The left hand side is a variable declaration. It's declaring a variable named x2
of type X
. The right hand side is a constructor invocation. We are invoking the public parameterless constructor of Y
; this will create a new instance of Y
. The entire statement is an assignment statement. We are assigning the result of the right hand side to the variable on the left hand side. The assignment is legal because all Y
s are polymorphically also X
s, since Y extends X
.
Upvotes: 1
Reputation: 41935
Yes it is legal and its not two constructors, just different reference types.
The instance is of Y
type but the reference is of X
type. So you won't be able to call methods of Y
on that.
new Y()
creates new instance of Y aka Runtime type
X x2 = new Y();
assigns it to reference of type X (aka Compile time type) which can hold Y, as X is superclass of Y
To test:
if(x2 instanceof Y){
System.out.println("Instance is of Y");
}
Upvotes: 0
Reputation: 482
Its legal to create an object using a constructor which use another constructor.
Upvotes: 0
Reputation: 22074
You can always assign a derived class to a variable of a type from the class hierarchy.
X x = new Y(); // is valid.
Y y = x; // is not valid without a cast, even though x is actually of class Y
Therefore it is valid to assign an object of Y to a variable of type X but not the other way around.
If you call functions on X and they are overriden in Y, then they will be called as well. However, if Y introduces new functions you can not call them from X of course.
Upvotes: 0
Reputation: 27802
x2
is really a Y
object at run-time. At compile-time, x2
will be treated like an X
object.
This is really useful for polymorphism, where at compile-time, you might not really know what type of object you will be dealing with, but you know you will be dealing with objects that inherit from X
.
Upvotes: 0