不可变类型需要复制构造函数吗?

Do immutable types need copy constructors?

说我有一个不可变的 DecimalNumber class:

public final class DecimalNumber {

    public final String str;

    public DecimalNumber(String str) { this.str = str; }
    public DecimalNumber(DecimalNumber copy) { this(copy.str); }

    public boolean isZero() {...}

    public DecimalNumber add(DecimalNumber other) {...}

    ...

}

我决定像这样实施 add

public DecimalNumber add(DecimalNumber other) {

    if (other.isZero())
        return /* the same object */

    ...

}

我应该 return this(更少的内存使用)还是复制的对象 new DecimalNumber(this)

我认为简单地 returning this 应该没问题,但是创建新对象是否有好处或理由,或者它是否曾经是首选?

我会 return 这个,如果一个对象真的是不可变的。您根本不需要两个肯定始终相等的实例。

https://docs.oracle.com/javase/tutorial/essential/concurrency/imstrat.html

为什么你对 returning this 感到奇怪?

如果你想要 return 一个新对象,你首先就不需要 if,所以 returning new DecimalNumber(this) 根本不是一个选择!

由于您的对象是不可变的,因此每当我们更改它时,我们都需要创建另一个副本。但是在这里,加零不会改变对象的值。 因此,我们可以 return 相同的对象。

参考 String.java 中的 concat() 代码:

public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        char buf[] = new char[count + otherLen];
        getChars(0, count, buf, 0);
        str.getChars(0, otherLen, buf, count);
        return new String(0, count + otherLen, buf);
    }

如您所见,return使用同一个对象没有什么坏处。

如果 class 是不可变的和最终的,那么你可以 return this

如果它不是最终的,您不能确定 this 实例真的是不可变的。您实际上可能正在处理一个添加可变状态的 subclass。

请注意,class 只有在以下情况下才是真正不可变的:

  • 它的所有字段都是最终的,即使是私有的。 (由于 Java 内存模型允许其他线程查看 non-final 字段的 unfinished/default 值,因此只有 getter 的 non-final 字段是不够的。)
  • 它的所有字段本身都是不可变的 class,或者对它们的访问受到限制,因此您可以确保它们永远不会被更改。

在您的情况下,这两个条件都得到满足,因为 String 是不可变的 class。如果您知道 class 的子 class 不存在,那么您可以(事实上,恕我直言)return this。为确保 class 的子 class 不存在,您可以将其设置为 final.

无需复制不可变值对象。因为它是不可变的,所以原件和副本在任何时候都是等价的,因此拥有两个副本是荒谬的。

我不仅会 return this 在你的例子中,我会更进一步,完全删除你的复制构造函数。

举个例子,Java String class 实际上有一个拷贝构造函数。但是所有这一切都是由没有经验的开发人员编写的代码,他们要么没有意识到它是不可变的(或者不理解这意味着什么),所以他们做 new String(aString)new String("Hello"),这什么都不做但会浪费内存和处理器周期。