1

在这样的情况下:

class A{
   public int x = 4;
   public void s3(){
      x = 3;
   }
   public void f(){
      x = 8;
      s3();
   }
}

class B extends A{
   public int x = 5;
   public void f(){
      x = 10;
      s3();
   }
}

A a = new B();
B b = (B) a;
a.f();
System.out.println(b.x);
System.out.println(a.x);

a.f()调用f()类的B,然后f()在赋值后调用s3()函数。此时,s3()仅定义在A和 将值 3 分配给 时xx是类拥有的变量的副本A。为什么s3()不使用x声明的 in B?理论上,B不应该有自己的s3()函数副本继承自A? (所以s3()继承自AinB应该使用x声明的 in B

4

3 回答 3

5

您对继承时应该做什么有误解。 extends是明智选择的保留字。B 扩展 A 的意义在于 B 是具有附加属性的 A 的子集。您不应该x在 B 中重新定义;A 应该处理x。通过x在子类中重新定义,您隐藏了超类的字段x(即使x引用不同的变量类型也是如此)。

A a = new B();
System.out.println(a.x);  //4 makes sense, since we are of class A
B b = (B) a;
System.out.println(b.x);  //5 makes sense, since we are of class B
a.f();
System.out.println(a.x);  //3 makes sense, since a.f() calls s3(), which sets A's x to 3
System.out.println(b.x);  //10 

10 来自打印 b 的 x,它通过调用 分配给 10 a.f(),然后调用s3()这就是第三个示例打印 3 的原因。要了解我的意思,请看这个:

  public void f()
   {
      x = 10; //sets B's x to 10
      s3();  //calls A's s3(), which sets A's x to 3.
   }
于 2013-05-21T23:28:45.240 回答
0

因为它是一样的。您没有对象的两个副本(“实例”),只有一个。

由于您创建的是一个B实例 ( new B()),因此它将使用 中定义的方法B。当然,当没有定义方法时B,它将使用超类方法实现。

因此,您只有一个x属性并s3强制它为3. 它工作正常。

于 2013-05-21T23:29:22.040 回答
0

为什么 s3() 不使用 B 中声明的 x?

通常,父类中的方法看不到子类中的成员变量。

我认为这样做:

B b = new B();
b.f();

至少足以重现您的部分困惑。这是 f() 在 B 中的样子:

class B extends A{
   public int x = 5;
   public void f(){
      x = 10;
      s3();
   }
}

f() 等价于:

   public void f(){
      this.x = 10;
      this.s3();
   }

所以调用 bf() 意味着 f() 相当于:

   public void f(){
      b.x = 10;
      b.s3();
   }

接下来,在 A 中的 s3() 方法内部会发生什么?s3() 看起来像这样:

public void s3(){
      x = 3;
   }

这相当于:

public void s3(){
      this.x = 3;
   }

'this' 是调用该方法的对象,从 f() 的最后一个示例中您可以看到它是 b。所以 s3() 相当于:

public void s3(){
      b.x = 3;
   }

所以 bx 被 3 覆盖了……嗯,没那么快!

B 的一个实例也从 A 继承了一个 x,只是在 B 内部,B 的 x 恰好遮住了来自 A 的 x。因此,B 中的 f() 方法从 B 分配给 x。在 s3() 内部然而,b 从 A 得到的 x 不再被遮蔽,并且就 A 而言,只有一个 x——来自 A 的那个。换句话说,对 bx 的查找采用不同的路径,具体取决于哪个类声明出现在。

在 s3() 执行之后,最终结果是 b 有两个 x 有两个不同的值。在 B 中的方法内部,来自 B 的 x 将是可见的,在 A 中的内部方法中,来自 A 的 x 将是可见的。在 B 中的内部方法中,可以使用 super 从 A 获取 x。

理论上,B 不应该从 A 继承自己的 s3() 函数副本吗?

不要考虑副本。考虑从类到类的指针,以及从类到查找表的指针。通常在计算机编程中,每个实例都有自己的实例变量,但方法由类中的所有实例共享。

于 2013-05-21T23:34:35.703 回答