【问题标题】:Why is this class mutable? [duplicate]为什么这个类是可变的? [复制]
【发布时间】:2019-01-14 07:30:08
【问题描述】:
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,即使在 getUrl 中也不能修改它,即使该方法被 Test 的任何子类覆盖。

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

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

  • 构造函数也不是私有的。

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

【问题讨论】:

  • 那是什么书?
  • make 方法 getUrl final 和 Test 的对象将是不可变的。
  • @AdityaNarayanDixit 并非如此,您仍然可以在子类中添加可变状态。

标签: java immutability


【解决方案1】:

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!

【讨论】:

  • 同意,但是仍然没有修改对象的状态(测试对象中url的值)。只是调用者现在得到了不同/错误的值。
  • @Ram 字段mutable 被添加为状态的一部分。因此,每次调用 getter 时都会更改状态。
  • “但是数据是不可修改的”——这取决于你的观点。对于客户端,字段是private,所以这个类唯一的“数据”就是你可以通过getUrl得到的。这是可以修改的,事实上即使只是简单地调用函数。想象一下,即使getUrl 返回相同的字符串,但仍会增加计数器...Test 的消费者无法确定(没有丑陋的技巧,例如检查运行时类型)调用getUrl 不会产生溢出有时会例外,但有时不会例外,具体取决于您的实例所在的位置。
  • @CompuChip 抓住了本质。我可以有点同意这是分裂的头发,但是,尽管Test 中的所有字段都是最终的并且不可变的。而Test 呈现给客户的接口绝对不是一成不变的。
  • 是的,但不可变并不意味着它为每个实例方法调用返回相同的值。它提供的值可以改变,并不意味着它的状态已经改变。您可以拥有一个不可变的RandomNumberGenerator(例如,您不能修改种子),但每次您要求它时都会返回一个新的随机数。
【解决方案2】:

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

如果一个类是有用的可继承的,通常很容易设计出一个完全不适合任何非人为目的的派生类型。一种语言甚至可以尝试阻止这种情况的唯一方法是极大地限制派生类型可以做的有用事情的范围。然而,除了一些特殊类型的类(通常与安全相关的类)之外,通常最好确保派生类可以做有用的事情,而不是担心它们可能会做人为和无用的事情。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2018-05-12
    • 1970-01-01
    • 1970-01-01
    • 2019-06-18
    • 2019-08-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多