复制构造函数访问其 class 的字段?

copy constructor accessing fields of its class?

我正在阅读 mutable/immutable 类 和 java 中的复制构造函数,偶然发现了 this example

在复制构造函数中,他使用如下 getter:

 /**
  * Copy constructor.
  */
  public Galaxy(Galaxy aGalaxy) {
    this(aGalaxy.getMass(), aGalaxy.getName());
    //no defensive copies are created here, since 
    //there are no mutable object fields (String is immutable)
  }

我的问题是,对于某些人来说,在复制构造函数中使用 getter 而不是仅仅访问字段,例如 (aGalaxy.aMass, aGalaxy.aName),除了这是一种良好的编码习惯之外,还有其他原因吗?你也可以找到这样做的例子,但我的意思是它纯粹是一种编码风格,还是在复制构造函数中使用 getters 有潜在的好处?

虽然在大多数情况下无害,但当子类选择覆盖您调用的 getter 时,这种做法可能会导致一些难以捕捉的错误。

这是一个简单的例子:

class Base {
    private final String name;
    public String getName() {return name;}
    public Base(String name) {
        this.name = name;
    }
    public Base(Base b) {
        this(b.getName());
    }
}
class Derived extends Base {
    public String getName() {
        return "["+super.getName()+"]";
    }
    public Derived(String name) {
        super(name);
    }
    public Derived(Derived d) {
        this(d.getName());
    }
}

请注意 Derived 如何覆盖 getName(),因此 Derived 的复制构造函数正在访问名称的修改版本,从而导致问题:

Derived orig = new Derived("hello");
Derived copy = new Derived(orig);
System.out.println(orig.getName()); // Prints [hello]
System.out.println(copy.getName()); // Prints [[hello]]

最后一张印刷品的方括号加倍,所以副本不是真正的副本。

使用 protected 变量或使你的 getters final 可以帮助你避免这个问题。

我认为这个问题的根本原因是让子类覆盖存储属性的 getter,所以我更喜欢让你的 getter final.

的方法

Demo.