简体   繁体   中英

java: create an objects from two constructors

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 ?

Those are NOT two constructors

 X x2 = new Y(); 
  • X is Type of variable
  • x2 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.

  • At compile time, x2 reference variable will be of type X
  • At runtime, x2 will refer to a subclass object ie 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 :

  • The statement X x = new X(); creates object of X with reference of X so calls someMethod of class X .
  • The statement 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.
  • For the statement Y y = new Y() , same explanation as of point 1.

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 .

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");
}

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 .

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.

使用使用另一个构造函数的构造函数创建对象是合法的。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM