java:从两个构造函数创建一个对象

时间:2013-08-02 13:13:25

标签: java object constructor

这是来自Kathy Sierra的“SCJP” 的示例:第2章 - 面向对象

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

使用两个构造函数创建对象是否合法?什么类型的对象是x2XY

6 个答案:

答案 0 :(得分:3)

这些不是两个构造函数

 X x2 = new Y(); 
  • X是变量类型
  • x2是引用变量,可以引用X,因此引用X的任何子类,在这种情况下,它可以引用Y
  • new Y()实际上在内存中创建了类Y的对象,变量x引用了该对象。

这是可能的,因为Y扩展了X因此它通过了IS-A测试。这是多态性的例子。超类型指的是子类型的对象。

  • 在编译时,x2引用变量的类型为X
  • 在运行时,x2将引用子类对象,即Y类型。

因此,如果类X中的某个方法被类Y中的方法覆盖,则类Y的方法将被调用,因为该对象的类型为{{ 1}}。

考虑这些课程。

Y

和另一个班级

public class X {

    public void someMethod(){
        System.out.println("we are in class X method");
    }
}

此输出

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

}

解释是:

  • 语句we are in class X method we are in class Y method we are in class Y method 参考X x = new X();创建X的对象,因此请调用X类的someMethod
  • 语句X创建X x2 = new Y();的引用变量,但是类X的对象,因此调用类Y的重写方法,因为重写的方法具有动态绑定。以及要调用的重写方法取决于对象类型。
  • 对于陈述Y,与第1点相同。

答案 1 :(得分:1)

x2的编译时类型为X,但运行时类型为Y。这意味着,当编译器需要推理x2时,它会认为x2X。但在运行时,x2的行为将是Y的行为。

因此,让我们更详细地解释一下。这合法:

x2.do2();

这是因为编译器认为x2XX没有名为do2的方法,只有Y。编译器不知道x2Y,它只知道x2的编译时类型是X

然而,这是合法的,并且会导致运行时异常:

((Y)x2).do2();

我们告诉编译器,看,我比x2知道的更多;我知道它是Y,因此只需发出以Y.do2作为接收方调用x2的指令。

此外,我们假设我们有一个接受Y s的方法:

void M(Y y) { }

然后这是合法的:

M(x2);

同样,这是因为编译器认为x2X,而不是所有X都是Y,所以它必须拒绝方法调用。

然而,这是合法的,并且会导致运行时异常:

M((Y)x2);

同样,我们告诉编译器,看,我知道的比x2更多;我知道它是Y,所以请相信我,并调用该方法,就像x2Y一样。

让我们进一步假设我们在X中定义了一个方法,并在Y中重写:

class X {
    void do1() {}
    void N() { System.out.println("X");
}

class Y extends X { void do2() {} 
    @Override
    void N() { System.out.println("Y");
}

现在,如果我们说:

x2.N();

我们会在控制台上看到 Y 。这是因为x2运行时类型为Y

所有这些都是人们在谈到polymorphism时的意思的部分

  

使用两个构造函数创建对象是否合法。

此声明中有两个构造函数:

X x2 = new Y();

只有一个构造函数。左侧是变量声明。它声明了一个名为x2的{​​{1}}类型的变量。右侧是构造函数调用。我们正在调用X的公共无参数构造函数;这将创建Y的新实例。整个陈述是一个赋值语句。我们将右侧的结果分配给左侧的变量。该作业是合法的,因为所有Y 多态也是Y s,因为X

答案 2 :(得分:0)

是的,它是合法的,它不是两个构造函数,只是不同的引用类型。

该实例属于Y类型,但引用属于X类型。因此,您无法在此处调用Y的方法。

new Y()创建了Y又名运行时类型

的新实例

X x2 = new Y();将其指定为类型X的引用(又名编译时间类型),它可以容纳Y,因为X是Y的超类

测试:

if(x2 instanceof Y){
   System.out.println("Instance is of Y");
}

答案 3 :(得分:0)

x2在运行时实际上是一个Y对象。在编译时,x2将被视为X对象。

这对多态非常有用,在编译时,你可能不知道你将要处理的对象类型,但是你知道你将处理从X继承的对象。 / p>

答案 4 :(得分:0)

您始终可以将派生类分配给类层次结构中的类型变量。

X x = new Y();  // is valid.
Y y = x;   // is not valid without a cast, even though x is actually of class Y

因此,将Y的对象分配给X类型的变量是有效的,但不是相反。

如果你在X上调用函数并在Y中覆盖它们,那么它们也会被调用。但是,如果Y引入新功能,当然不能从X调用它们。

答案 5 :(得分:0)

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