简体   繁体   English

子类中的超级构造函数-Java

[英]Super constructor in a subclass - Java

Considering the following code example, can someone help to explain why the result of B b3= new B (20, 50) ; 考虑下面的代码示例,有人可以帮助解释为什么B b3= new B (20, 50) ; System.out.println(b3) ; System.out.println(b3) ; is A:20, B:(10, 61) ? A:20, B:(10, 61)吗? I thought through calling the super (x) , we uses the A(int x) {this x =x;} and int x of B has been changed to 20. 我以为通过调用super (x) ,我们使用A(int x) {this x =x;} ,B的int x已更改为20。

PS: I'm looking for the reason behind how it works but not how to print out certain value in B. 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 + ")";
   }
}

As many others have meanwhile pointed out, attributes are resolved statically in Java, while methods are resolved dynamically. 正如许多其他人同时指出的那样, 属性是在Java中静态解析的,而方法是动态解析的。 This means that attributes shadow while methods overwrite . 这意味着方法覆盖时属性阴影 Casting a variable up to its superclass (as happens implicitly to the this pointer) will not affect how methods are resolved but does change how attributes are. 将变量强制转换到其超类(隐式发生在this指针上)不会影响方法的解析方式,但会改变属性的方式。

The second thing is that even if A 's constructor in your example were to assign to Bx , it would happen before the B -part of the object is constructed (as objects are constructed starting with Object 's constructor and then walking down the class hierarchy [1]) and the constructor of B would overwrite it. 第二件事是, 即使您示例中的A的构造函数分配给Bx ,它也会在对象的B部分被构造之前发生(因为对象是从Object的构造函数开始构造的,然后向下走该类层次结构[1]), B的构造函数将覆盖它。 You can verify that the constructor of A sees an uninitialized B by (only for academic purpose, please) downcasting the this pointer in A 's constructor and inspecting Bx . 您可以验证A的构造函数是否看到未初始化的B是(仅出于学术目的)在A的构造函数中this指针向下转换并检查Bx It will be 0. 它将是0。

class A {
    int x;
    A(int x) {
        System.out.printf("A() before: A.x = %d%n", this.x);  // 0
        System.out.printf("A() before: B.x = %d%n", (B) this).x);  // 0
        this.x = x;
        System.out.printf("A() after: A.x = %d%n", this.x);  // 7
        System.out.printf("A() after: B.x = %d%n", (B) this).x);  // 0
    }
}

class B extends A {
    int x = 10;
    B() {
        super(7);
        System.out.printf("B(): A.x = %d%n", super.x);  // 7
        System.out.printf("B(): A.x = %d%n", this.x);  // 10
    }
}

Notes: 笔记:

  1. This might seem illogic: After all, isn't A 's constructor called from within B 's? 这似乎是不合逻辑的:毕竟,不是从B的内部调用 A的构造函数吗? It turns out that super() is not a normal method invocation but a special feature. 事实证明, super()不是正常的方法调用,而是一种特殊功能。

Your class B is shadowing the int x from A . 您的班级B正在使Aint x蒙上阴影。 If you don't do that, 如果你不这样做

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 + ")";
  }
}

Then your code would work as you expected. 然后您的代码将按预期工作。 Your shadow means there are literally two variables named x . 您的影子意味着实际上有两个名为x变量。 To get the parent one you need super.x (as you already did). 要获得父代,您需要super.x (就像您已经做的那样)。

we uses the A(int x) {this x =x;} and int x of B has been changed to 20. 我们使用A(int x){this x = x;},B的int x已更改为20。

Actually, no. 其实没有 It hasn't been changed to 20 . 尚未更改20 It was never 10 in the first place. 从来没有10

There are two separate x instance variables, one declared in A and one in B . 有两个单独的x实例变量,一个在A声明,一个在B

  • In A (int x) { this.x = x; } A (int x) { this.x = x; } A (int x) { this.x = x; } , the this.x is the x declared in A . A (int x) { this.x = x; }this.x是在A声明的x

  • In class B extends A { int x = 10; ... class B extends A { int x = 10; ... class B extends A { int x = 10; ... the x is a different one. class B extends A { int x = 10; ... x是另外一个。

When you assign to one of the x variables, it does not alter the other one. 当您分配给x变量之一时,它不会更改另一个变量。 They are distinct . 它们是截然不同的


What this problem / example is intended to illustrate is shadowing ... where one variable in the superclass gets "sort of hidden" by another variable in the subclass. 这个问题/示例旨在说明的问题是阴影 ...超类中的一个变量被子类中的另一个变量“隐藏”。 From a design / coding perspective, it is a bad idea. 从设计/编码的角度来看,这是一个坏主意。 You should avoid doing this in real code. 您应该避免在真实代码中这样做。

The reason is that you have two x variables -- one in A and one in B , so when you call super(x) , it goes to the constructor in A , which, because it's in A , assigns A 's x to the argument of super(x) . 原因是您有两个x变量-一个在A ,一个在B ,因此,当您调用super(x) ,它将转到A的构造函数,因为它在A ,所以将Ax赋给了super(x)参数。 So it sets super.x to 20 , but doesn't change the x in B . 因此,它将super.x设置为20 ,但不更改Bx So B s x stays at the 10 it was originally initialized as. 因此B s x停留在最初初始化为的10处。

B(int x, int y) constructor has same argument name as instance variable so x pass to super constructor A will be the one which is pass to constructor B and it is not related to instance variable x. B(int x,int y)构造函数的名称与实例变量相同,因此传递给超级构造函数A的x将成为传递给构造函数B的变量,并且与实例变量x不相关。 Instance variable x(defined as int x=10;) value will be change only when refer by this.x from B's constructor. 实例变量x(定义为int x = 10;)的值只有在B的构造函数中由this.x引用时才会更改。 'this' keyword used to refer to object that call the function. “ this”关键字用于引用调用该函数的对象。 So no matter what you pass B(any value, y), it will display 10 for x as output as we are not changing value of x. 因此,无论您传递什么B(任何值y),由于我们不更改x的值,它将为x显示10作为输出。

Does this make sense? 这有意义吗?

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

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