![](/img/trans.png)
[英]How to create objects for parameterized constructors in Java, when we have two classes with the same attributes?
[英]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();
}
}
使用两个构造函数创建对象是否合法? 什么类型的对象是x2
: X
还是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
,它将假设x2
是X
但在运行时, x2
的行为将是Y
的行为。
所以让我们更详细地解释一下。 这不合法:
x2.do2();
这是因为编译器认为x2
是X
而X
没有名为do2
的方法,只有Y
这样做。 编译器不知道x2
是Y
,它只知道x2
的编译时类型是X
但是,这是合法的, 不会导致运行时异常:
((Y)x2).do2();
我们告诉编译器,看,我比你更了解x2
; 我知道它是Y
,所以只发出调用Y.do2
并用x2
作为接收器的指令。
另外,我们假设我们有一个接受Y
的方法:
void M(Y y) { }
那么这不合法:
M(x2);
同样,这是因为编译器认为x2
是X
,并非所有X
都是Y
s,所以它必须拒绝方法调用。
但是,这是合法的, 不会导致运行时异常:
M((Y)x2);
再一次,我们告诉编译器,看,我知道的比x2
; 我知道它是Y
,所以请相信我,并调用该方法,就像x2
是Y
。
让我们进一步假设我们有一个在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();
只有一个构造函数。 左侧是变量声明。 它声明了一个名为x2
的X
类变量。 右侧是构造函数调用。 我们正在调用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.