这个对象是否可变?

时间:2014-01-27 10:39:54

标签: java mutable

如果我有这样的课程:

public class MyObject {
    private int myField = 2;
    public void setMyField(int f) {
        this.myField = f;
    }
}

这个类的对象是否可变? 谢谢!

6 个答案:

答案 0 :(得分:10)

当然 - 如果你想要它是不可变的,那么你需要像:

public class MyObject {
    private final int myField;

    public MyObject(int f) {
      myfield = f;
    }

    public int getMyField() {
        return myField;
    }
}

答案 1 :(得分:9)

  

可变对象具有可以更改的字段,不可变对象   在创建对象后没有可以更改的字段。

答案 2 :(得分:6)

您已经有几个答案,其中" "。

我想添加" " (如果我会大胆,我会说" "; - )

是的,此类的对象似乎是可变的,因为它提供了一个更改字段的setter。但是,由于它没有该字段的getter,也没有任何其他getter取决于该字段,并且由于该字段是私有的,因此目前无法读取该状态。

换句话说:对象具有状态,但它不会将任何状态暴露给外部。

我会称这个对象为#34;实际上是不可变的"。

有一些设计模式,其中对象是"有效地不可变",例如"懒惰初始化"一个"不可变对象"。

注意:存在"有效不可变的概念"在Brian Goetz的“Java Concurrency in Practice”第3.5.4节中讨论。

答案 3 :(得分:1)

是的,这个类的对象是可变的。该类的设计者不能通过任何技术手段(在现有的Java中)禁止对象的消费者观察和修改该领域的内容。

私人是关于该字段的预期用途的明确声明的合同 - 该合同可以被破坏,例如用反射。

在创建之后不提供任何更改对象数据的方法也可以是(隐式声明的)有关预期用途和可变性的合同 - 此合同也可以被破坏,就像任何需要两个合规方的合同一样。

编辑:除非有另一方能够强制执行 - 就像在Java中一样,SecurityManager会阻止您在运行时更改 final 字段。

答案 4 :(得分:0)

,您的对象是可变的,因为在使用setter创建实例后,myField的值可以更改。

使用final字段可以实现不变性,因为一旦初始化变量,它将不允许您更改变量的值。

@JakubK的回答指出如何让你的班级成为永恒的。

但声明引用final不会使对象被final指向。

例如:

class MyObject{
    private final List<Integer> list = new ArrayList<Integer>();

    public List<Integer> getList(){
        return list;
    }
} 

我可以通过做类似的事情来改变从外部向list添加新元素

instance.getList().add(1); //mutates the list

此示例不是不可变的,因为List可以被其他人更改。

答案 5 :(得分:0)

要定义某些东西是否可变,必须定义由此封装的状态。如果MyObject指定其状态包含Reflection将为myField报告的值,则它是可变的。如果该字段未被指定为对象的可观察状态的一部分,那么它可能被认为是不可变的。

更具体地说,只有当一个人可以在类,任何顺序和任何时间(甚至在多个线程上)执行任何记录操作的组合时,我认为一个类是不可变的,并且没有任何记录的行为受其他任何影响的任何方面。当且仅当该更改会影响另一个方法调用的某些记录的行为方面(对于相同或不同的方法)时,方法可能更改私有字段的内容这一事实是相关的。例如,我会说String.hashCode()修改hash字段的事实不会使String变为可变,因为hashCode()返回的值不受是否影响该领域先前已经写过。如果一个类有hashCode方法,如果一个字段为空,则生成一个随机数并将其存储在该字段中,否则直接返回该值,这样的类将是可变的,除非它确保该字段经过测试并设置为原子操作。在没有这种保证的情况下,几乎可以同时调用hashCode()来产生不同的值,从而将来调用不同的值,这些值与至少其中一个不同(暗示对象的状态)在返回奇数球值的召唤和后来的召唤之间发生了变化。