使用除公共字段之外的getter / setter来实现二进制兼容性?

时间:2012-04-04 19:31:52

标签: java getter-setter binary-compatibility

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

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

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

2 个答案:

答案 0 :(得分:3)

  

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

这将是非常令人惊讶的:

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

  

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

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

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

也就是说,字段访问表达式的二进制名称不是指声明字段的类型,而是指我们用于访问该字段的主表达式的类型,因此该类型的任何超类都声明该字段,编译器 required 相同的字段引用发送到类文件中。

的确,当我刚才尝试从

演变的时候
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年前被宣布为报废。无论哪种方式,也许你应该使用更好/更新的书?

答案 1 :(得分:0)

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

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