子类中的超级构造函数-Java
考虑以下代码示例,是否有人可以帮助解释为什么子类中的超级构造函数-Java,java,class,inheritance,constructor,super,Java,Class,Inheritance,Constructor,Super,考虑以下代码示例,是否有人可以帮助解释为什么b3的结果=新的B(20,50)System.out.println(b3);是A:20,B:(10,61)?我想通过调用super(x),我们使用A(intx){thisx=x;},而B的intx已经更改为20 PS:我在寻找它工作原理背后的原因,而不是如何在B中打印出某些值 class A { int x; A(int x) { this.x = x; } public String toString() { r
b3的结果=新的B(20,50)代码>System.out.println(b3)
;是A:20,B:(10,61)
?我想通过调用super(x)
,我们使用A(intx){thisx=x;}
,而B的intx已经更改为20
PS:我在寻找它工作原理背后的原因,而不是如何在B中打印出某些值
class A {
int x;
A(int x) {
this.x = x;
}
public String toString() {
return "A:" + x;
}
}
class B extends A {
int x = 10;
int y = x+1;
B(int x, int y) {
super(x);
this.y = this.y + y;
}
public String toString() {
return "A:" + super.x + ", B:(" + x + "," + y + ")";
}
}
您的类B
正在从A
隐藏int x
。如果你不这样做
class B extends A {
// int x = 10; // <-- shadows A.x
int y = x+1;
B(int x, int y) {
super(x);
this.y = this.y + y;
}
public String toString() {
return "A:" + super.x + ", B:(" + x + "," + y + ")";
}
}
B类扩展了A类{
//int x=10;//
我们使用A(intx){thisx=x;}并且B的intx已更改为20
事实上,没有。它没有被更改为20
。它从一开始就不是10
有两个独立的x
实例变量,一个在A
中声明,另一个在B
中声明
- 在
A(intx){this.x=x;}
中,this.x
是A
中声明的x
- 在
类中,B扩展了A{int x=10;..
中的x
是一个不同的类
当您指定一个x
变量时,它不会改变另一个变量。它们是不同的
此问题/示例旨在说明的是阴影…超类中的一个变量“有点隐藏”通过子类中的另一个变量。从设计/编码的角度来看,这是一个坏主意。您应该避免在实际代码中这样做。原因是您有两个x
变量-a
和B
,因此当您调用super(x)时
,它进入A
中的构造函数,因为它在A
中,所以将A
的x
赋值给super(x)的参数
。因此它将super.x
设置为20
,但不更改B
中的x
。因此B
sx
保持在最初初始化为的10
位置。B(int x,int y)构造函数与实例变量具有相同的参数名,因此传递给超级构造函数A的x将是传递给构造函数B的x,它与实例变量x无关。实例变量x(定义为int x=10;)只有当从B的构造函数中引用此.x时,值才会更改。“this”关键字用于引用调用该函数的对象。因此,无论您传递B(任何值,y)什么,它都将为x显示10作为输出,因为我们不会更改x的值
这有意义吗?正如许多其他人同时指出的那样,属性在Java中是静态解析的,而方法是动态解析的。这意味着属性在方法覆盖时是阴影。将变量向上转换为其超类(这隐式地发生在这个
指针上)不会影响方法的解析方式,但会更改属性的解析方式
第二件事是,即使在您的示例中A
的构造函数被分配给B.x
,它也会发生在对象的B
部分被构造之前(因为对象是从对象的构造函数开始构造的,然后沿着类层次结构[1])而B
的构造函数将覆盖它。您可以通过(仅出于学术目的)在A
的构造函数中向下投射此指针并检查B.x
来验证A
的构造函数是否看到未初始化的B
。它将为0
A类{
int x;
A(整数x){
System.out.printf(“A.x=%d%n”之前的A(),this.x);//0
System.out.printf(“B.x=%d%n之前的A(),(B)this.x);//0
这个.x=x;
System.out.printf(“A.x=%d%n”之后的A(),this.x);//7
System.out.printf(“B.x=%d%n”之后的A(),(B)this.x);//0
}
}
B类扩展了A类{
int x=10;
B(){
超级(7);
System.out.printf(“B():A.x=%d%n”,super.x);//7
System.out.printf(“B():A.x=%d%n”,this.x);//10
}
}
注意事项:
这似乎不合逻辑:毕竟,A
的构造函数不是从B
内部调用的吗?事实证明,super()
不是一个普通的方法调用,而是一个特殊的特性
我认为这是一个演示阴影的学术示例。通过在B
的toString
方法中正确使用x
和super.x
,OP显示出意识到了这一点。@5gon:这似乎不清楚。如果OP意识到了这一点,我想他不会期望B的x发生变化。谢谢!你是指super(x)b中的super(7)不会改变b.x?但我认为这是我们使用超级构造函数来改变b的值的方式谢谢!但是如果在你的例子中,b中的super(7)只改变super.x,而不是这个.x,那么我们如何使用super()构造函数在这种情况下更改这个.x?冒着听起来很傻的风险:一点也不。为什么要使用super
来更改您自己类的属性。如果您愿意,您可以说this.x=7
。但我想我们使用super()调用超类构造函数来构造子类对象?即B(){super()}将使用a中的构造函数生成B类对象?否,super()
始终调用基类构造函数,并且它将始终构造基类对象。如何在“可能的工作”中使用构造函数创建“B类对象”呢?是的,我想您现在已经得到了。任何类型B的对象都包含一个对象(有时称为子对象)类型A和中的super()
构造函数中的引用该子对象(如果您知道C,请将其视为struct A{int x;};struct B{struct A super;int x;}
),是的,base=parent。