18

以下是我的项目代码的一部分:

public class Body extends Point{
    public double x, y, mass;

    public Body() {
        x = y = mass = 0;
    }

    public Body(double x, double y, double mass) {
        this.mass = mass;
        this.x = x;
        this.y = y;
    }
}

public class Point {
    public double x;
    public double y;

    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}

我很快意识到这样做会在 Body 类中创建两个名为 x 的变量,并在 Body 中创建另外两个名为 y 的变量。这怎么可能,为什么 Java 甚至允许它?

我认为这是类 Body 的正确代码:

public class Body extends Point{
    public double mass;

    public Body() {
        super();
        mass = 0;
    }

    public Body(double x, double y, double mass) {
        super(x,y);
        this.mass = mass;
    }
}

谢谢你的时间

4

4 回答 4

17

从某种意义上说,您正在覆盖超类的字段。但是由于没有字段重载(您只有一个给定名称的变量,类型无关紧要),因此意外地做起来要容易得多。这被称为变量“隐藏”或“阴影”。所以,你是对的,你最终会得到两个同名的字段。

你的第二个例子是正确的。它们是从超类继承的,并且由于它们没有被声明为私有的,因此它们对子类是可见的。直接引用超类的字段通常是不好的做法,除非有充分的理由,否则它们应该声明为私有的。您调用超级构造函数的示例是最好的方法。

此外,如果您隐藏了另一个同名字段,您仍然可以将它们称为 super.x、super.y、vs.this.x、this.y,您应该尽可能避免这种情况。

于 2009-04-21T13:49:16.470 回答
7

是的,您将有两个变量,一个隐藏另一个。允许它是有道理的,原因有两个:

  1. 假设你有一个作者不知道的基类Base和派生类。作者是否应该永远无法添加任何字段,仅仅因为派生类可能共享这些字段?还是应该在更改实际上不影响正确性时停止编译?DerivedBaseBaseDerivedBase
  2. 您的字段几乎应该始终是私有的,此时名称是否重复并不重要——“一方”都不会知道另一方的变量。
于 2009-04-21T13:52:11.393 回答
4

除了其他人所说的:是BodyPoint?不,Body有一个 position 类型的属性Point。所以Body大概不应该延长Point。如果你摆脱了继承(实现),那么你就摆脱了很多问题。那和使用private(不是protected!)和final自由。

于 2009-04-21T13:57:59.133 回答
1

我很快意识到这样做会在 Body 类中创建两个名为 x 的变量,并在 Body 中创建另外两个名为 y 的变量。这怎么可能,为什么 Java 甚至允许它?

实际上不,您没有创建两个具有相同名称的变量,显然编译器不应该也不会允许这样做。

所做的是隐藏定义为x和的现有变量y,这意味着 Body.x 和 Body.y 本质上与 Point.x 和 Point.y 的名称重叠,使得后两个变量完全无法从 Body 类中访问(链接到“阴影”的 Java 语言规范定义)。

名称阴影通常被认为是一种不好的做法和错误的原因,如果您打开 javac 编译器警告,编译器将尽职尽责地警告您。

于 2009-04-21T13:51:58.540 回答