5

我正在阅读“实用 API 设计”并找到以下段落:

在 JVM 规范中可以找到更喜欢方法而不是字段的另一个原因。您可以将方法从一个类移动到其超类之一,并且仍然保持二进制兼容性。因此,最初作为 Dimension javax.swing 引入的方法.JComponent.getPreferredSize(Dimension d) 可以在新版本中删除并移至 Dimension java.awt.Component.getPreferredSize(Dimension d),因为 JComponent 是 Component 的子类。这样的变化在 JDK 1.2 中确实发生过,这只能是因为字段被方法封装了。这样的操作是不允许对字段进行的。一旦在一个类中定义了一个字段,它就必须永远留在那里以保持二进制兼容性,这是另一个原因保持字段私有

因为我同意使用 getter/setter 是更好的方法。但我不明白为什么将公共字段移动到父类会破坏二进制兼容性?只要它在父类中是公共的,您仍然应该能够通过子类访问该字段。

4

2 回答 2

3

一旦在类中定义了一个字段,它就必须永远留在那里以保持二进制兼容性

这将是非常令人惊讶的:

Java 语言规范 Java SE 7 版定义了非限定字段访问表达式的二进制名称,如下所示:

给定一个表示类 C 中的字段访问的合法表达式,引用在(可能不同的)类或接口 D 中声明的名为 f 的非常量(第 13.4.9 节)字段,我们定义字段引用的限定类型如下:

  • 如果表达式是 Primary.f 的形式,那么:
    • 如果 Primary 的编译时类型是交集类型 (§4.9) V1 & ... & Vn,则引用的限定类型是 V1。
    • 否则,Primary 的编译时类型是引用的限定类型。

(Java 1.5 的语言规范使用完全相同的措辞)

也就是说,字段访问表达式的二进制名称并不指声明该字段的类型,仅指我们用于访问该字段的主表达式的类型,因此无论该类型的哪个超类声明该字段,编译器都是需要相同的字段引用发送到类文件中。

的确,当我刚刚尝试从

package p;

public class Super {

}

package p;

public class Sub extends Super {
    public String message;

    @Override
    public String toString() {
        return message;
    }
}

package p;

public class Super {
    public String message;
}

package p;

public class Sub extends Super {
    @Override
    public String toString() {
        return message;
    }
}

无需重新编译

package p;

public class Main {
    public static void main(String[] args) {
        Sub sub = new Sub();
        sub.message = "hello";
        System.out.println(sub);
        System.out.println(sub.message);
    }
}

我仍然收到了输出

hello
hello

, 不是LinkageError.

总而言之,这种说法对于 Java 7 是不正确的。对于 JDK 1.4 或更早版本可能是正确的,它在 5 年多前被宣布终止生命周期。无论哪种方式,也许您应该使用更好/更新的书?

于 2012-04-04T21:34:39.023 回答
0

如果我没记错的话,这本书解释了这一点,但我目前手头没有。我认为这是关于 Java 语言和类文件格式(Java 以外的其他语言也使用)之间的细微差别。

在之前或之后检查一下这本书。询问您是否对该部分有更多问题。

于 2012-04-04T19:39:04.290 回答