【问题标题】:Super constructor in a subclass - Java子类中的超级构造函数 - Java
【发布时间】:2014-11-06 03:13:02
【问题描述】:

考虑以下代码示例,有人可以帮助解释为什么B b3= new B (20, 50) ;的结果System.out.println(b3);是A:20, B:(10, 61) 吗?我想通过调用super (x),我们使用A(int x) {this x =x;},并且B的int x已更改为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 + ")";
   }
}

【问题讨论】:

    标签: java class inheritance constructor super


    【解决方案1】:

    您的班级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 + ")";
      }
    }
    

    然后您的代码将按您的预期工作。你的影子意味着实际上有两个变量名为x。要获得父母,您需要super.x(就像您已经做过的那样)。

    【讨论】:

    • 我认为这是一个展示阴影的学术例子。通过在BtoString 方法中正确使用xsuper.x,OP 可以意识到这一点。
    • @5gon:这似乎不清楚。如果 OP 知道这一点,我认为他不会期望 B 的 x 被改变。
    【解决方案2】:

    我们使用 A(int x) {this x =x;} 并且 B 的 int x 已更改为 20。

    实际上,没有。它尚未更改20。一开始就不是10

    有两个独立的x 实例变量,一个在A 中声明,一个在B 中声明。

    • A (int x) { this.x = x; } 中,this.x 是在A 中声明的x

    • class B extends A { int x = 10; ... 中,x 是不同的。

    当您分配给x 变量之一时,它不会改变另一个变量。它们是不同的


    这个问题/示例旨在说明的是 shadowing ...其中超类中的一个变量被子类中的另一个变量“隐藏”。从设计/编码的角度来看,这是一个坏主意。您应该避免在真实代码中这样做。

    【讨论】:

      【解决方案3】:

      原因是你有两个x变量——一个在A中,一个在B中,所以当你调用super(x)时,它会转到A中的构造函数,因为它是在A 中,将Ax 分配给super(x) 的参数。所以它将super.x 设置为20,但不会更改B 中的x。所以Bs x 停留在10,它最初被初始化为。

      【讨论】:

        【解决方案4】:

        B(int x, int y) 构造函数与实例变量具有相同的参数名称,因此传递给超级构造函数 A 的 x 将是传递给构造函数 B 的那个,它与实例变量 x 无关。实例变量 x(定义为 int x=10;) 值只有在 B 的构造函数中通过 this.x 引用时才会改变。 'this' 关键字用于引用调用函数的对象。所以无论你传递什么 B(any value, y),它都会为 x 显示 10 作为输出,因为我们没有改变 x 的值。

        这有意义吗?

        【讨论】:

        • 谢谢!你的意思是b中的super(x)不会改变b.x?但我认为这是我们使用超级构造函数来改变 b 值的方式
        【解决方案5】:

        正如许多其他人同时指出的那样,属性在Java中是静态解析的,而方法是动态解析的。这意味着属性 shadow 而方法 overwrite。将变量转换为它的超类(隐含地发生在 this 指针上)不会影响方法的解析方式,但会改变属性的方式。

        第二件事是即使你的例子中A的构造函数被分配给B.x,它也会发生在之前B-对象的一部分被构造(因为对象是从Object 的构造函数开始构造的,然后沿着类层次结构[1]),B 的构造函数将覆盖它。您可以验证A 的构造函数是否看到未初始化的B,方法是(请仅出于学术目的)在A 的构造函数中向下转换this 指针并检查B.x。它将是 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
            }
        }
        

        注意事项:

        1. 这可能看起来不合逻辑:毕竟,A 的构造函数不是从B 内部调用的吗?原来super()并不是普通的方法调用,而是一个特殊的特性。

        【讨论】:

        • 谢谢!但是如果在你的例子中说,B中的super(7)只改变super.x而不改变this.x,那么在这种情况下我们如何使用super()构造函数来改变this.x?
        • 冒着听起来很傻的风险:一点也不。为什么要使用super 来更改自己类的属性。如果你愿意,你可以直接说this.x = 7
        • 但我以为我们使用 super() 调用超类构造函数来构造子类对象?即 B() {super()} 将使用 A 中的构造函数生成一个 B 类对象?
        • 不,super() 总是调用基类构造函数,它总是会构造基对象。 “使用 A 中的构造函数创建 B 类对象”应该如何工作?
        • 是的,我想你现在明白了。任何类型 B 的对象都包含类型 A 的对象(有时称为子对象),而 super() 构造函数中的 this 引用该子对象。 (如果你知道 C,可以把它想象成 struct A { int x; }; struct B { struct A super; int x; }。)是的,base = parent。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2011-06-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-10-20
        • 1970-01-01
        相关资源
        最近更新 更多