0

我理解不可变意味着它是一个在实例化后不会改变状态的对象。但是在这行代码中,当声明数组值时,我没有看到 Final。这个类是不可变的吗?任何人都可以解释如何找出答案。谢谢

public class A {
private double[] values;
public double[] getValues(){
return values;
 }
}
4

4 回答 4

1

正如其他人所写的那样,这个对象在其状态下被认为是可变的。它不可变的是你不能交换它持有的数组。但是您可以更改数组的内容 (getValues()[0] = 10;)。

要将其转换为不可变对象,您必须使用 List 而不是数组。使用 List 您可以使用Collections的方法unmodifiableList将给定列表转换为您可以保存地暴露给外部的版本。如果 getValues() 的调用者在不可修改的列表上使用 add 或 remove ,它将导致 UnsupportedOperationException 使您的对象保存不被修改。

如果您需要坚持使用数组,则需要提供数组的副本 (System.arraycopy) 或克隆 (clone())。

通常,如果您不能更改对象的属性(包括从超类继承的属性),则对象被认为是不可变的。这通常也包括属性值,但这是一个模糊的定义。

例如,如果您有一个包含指向文档文件的 File 实例的类,并且该 File 实例不能更改,则该类被认为是不可变的(它提供的信息永远不会改变),但它指向的文档可以被变异并且每次都变了。所以它实际上是一条模糊的线(请记住,在您的示例中,您不能更改数组,但不能更改数组的内容)。

于 2013-10-17T17:35:24.403 回答
0

是的,粘贴的代码没有关联任何 final 关键字,也没有不可变的行为。

好吧,我想提出一些与在 java 中编写不可变类相关的关键指南:

1.) 确保类不能被覆盖 - 使类成为最终类,或使用静态工厂并保持构造函数私有

2.) 将字段设为私有和最终强制调用者在一个步骤中完全构造一个对象,而不是使用无参数构造函数与对 setXXX 方法的后续调用相结合(即避免 Java Beans 约定)

3.) 不要提供任何可以以任何方式改变对象状态的方法——不仅仅是 setXXX 方法,而是任何可以改变状态的方法

4.) 如果类有任何可变对象字段,那么当它们在类和它的调用者之间传递时,它们必须被防御性地复制

于 2013-10-17T17:09:56.620 回答
0
A a = new A();
a.getValues()[0] = 1.2;

只要值不为空,这将起作用。但是,您将无法将值重新分配给新数组。那就是:a.getValues() = new double[5];行不通。

该类不是不可变的,因为我可以更改值,而不是重新分配它。

于 2013-10-17T17:17:05.103 回答
0

这是一个简单的验证。这些值被初始化为 1,2。

使用 getter 和引用,可以在创建对象后更改数组中第一项内的值

public class A {
    private double[] values;

    public double[] getValues() {
        return values;
    }

    public static void main(String[] args) {
        A test = new A();
        test.values= new double[]{1, 2};

        double[] valuesref = test.getValues();
        valuesref[0] = 10;

        for (int i = 0; i < test.values.length; i++) {

            System.out.println(test.values[i]);    
        }
    }
}

如果 getValues() 返回数组的副本,则可以避免这种情况。

于 2013-10-17T17:20:03.680 回答