Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
子类中的超级构造函数-Java_Java_Class_Inheritance_Constructor_Super - Fatal编程技术网

子类中的超级构造函数-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
s
x
保持在最初初始化为的
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。