为什么这堂课是可变的?

时间:2019-01-14 07:30:08

标签: java immutability

public class Test {
    private final String url;
    public Test(String url) {
        this.url = url;
    }
    public String getUrl() {
        return url;
    }
}

Test类具有:

  1. 只有一个实例变量是私有和最终的。
  2. 没有二传手。
  3. 初始化实例变量的唯一方法是通过构造函数。
  4. 并且一旦设置了URL,即使该方法被Test的任何子类覆盖,即使在getUrl中也无法对其进行修改。

但是我正在读的一本书说上面的Test类是可变的,因为:

  • 这两个类都不是最终的,因此可以对其进行扩展,并且子类可以覆盖实例方法。但是Test类除了构造函数外实际上没有任何实例方法。

  • Nor是私有的构造函数。

能否请您帮助我理解为什么Test类是可变的?

2 个答案:

答案 0 :(得分:58)

尽管Test的直接实例是肯定的,但不能保证Test的任意实例都是不可变的。但是请考虑以下子类:

public class MutableTest extends Test {
        private int mutable;
        public MutableTest(String url) {
                super(url);
        }

        @Override
        public String getUrl() {
                return super.getUrl() + mutable++;
        }
}

然后您可以编写如下内容:

Test instance = new MutableTest("http://example.com/");
String firstGet = instance.getUrl();
String secondGet = instance.getUrl();
assertEquals(firstGet, secondGet); // Boom!

答案 1 :(得分:0)

接收到已知为Test类型的对象的对象将知道该对象是不可变的。但是,接收类型为Test的非空引用的对象将没有语言定义的方式来确保由此标识的对象是不可变的。有些人似乎将此视为主要问题。但是,总的来说,我认为不应该。

如果一个类可以有用地继承,那么通常很容易构造一个派生类型,该类型将完全不适合任何非故意用途。一种语言甚至试图阻止这种情况的唯一方法就是极大地限制派生类型可以做的有用事情的范围。但是,在少数几种特殊的类(通常是与安全性有关的类)之外,通常最好确保派生类可以做有用的事情,而不用担心它们做作的和无用的事情的可能性。