繁体   English   中英

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

[英]java: create an objects from two constructors

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

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

那些不是两个构造函数

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

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

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

因此,如果类X中的方法被类Y中的方法覆盖,则将调用类Y的方法,因为该对象的类型为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称为因为覆盖的方法有动态结合。 以及要调用的重写方法取决于对象类型。
  • 对于语句Y y = new Y() ,与第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的方法:

void M(Y y) { }

那么这合法:

M(x2);

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

但是,这是合法的, 不会导致运行时异常:

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

所有这些都是人们谈到多态时的意思的一部分

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

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

X x2 = new Y();

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

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

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

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

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

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

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调用它们。

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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