1

我们知道final关键字创建了对对象的常量引用。例如:

final Object object = new Object();

但是,在这种情况下,只有对对象的引用是固定的,在程序的执行运行时不能更改。我仍然可以在该对象上调用 setter 方法并更改其数据成员的值。有没有办法可以在 Java 中防止这种情况(相当于 C++ 中的 const )?

我理解一种方法,我不应该为这个对象类定义设置器,或者应该只允许设置一次值,但是如果我想将此对象作为参数传递给函数并且不希望该函数更改此对象的值怎么办?数据成员。我可能仍想更改函数之外的值。

在这种情况下,函数原型应该是什么?

4

4 回答 4

4

诀窍是为对象定义一个只读接口,并将设置器仅放入类中,如下所示:

public interface ConstInterface {
    int getFirst();
    String getSecond();
}

public class MutableClass implements ConstInterface {
    private int _first;
    private String _second;
    int getFirst() {
        return _first;
    }
    void setFirst(int f) {
        _first = f;
    }
    String getSecond() {
        return _second;
    }
    void setSecond(String s) {
        _second = s;
    }
}

final ConstInterface obj = new MutableClass();

此时,您可以obj通过其界面以只读方式访问。如果您需要设置属性,请obj转换为MutableClass并调用设置器。

于 2012-10-29T06:29:48.563 回答
3

但是,如果我想将此对象作为参数传递给函数,并且不希望该函数更改此对象的数据成员的值,该怎么办。我可能仍想更改函数之外的值。

在这种情况下,您应该只将对象的克隆而不是对象本身传递给方法。

于 2012-10-29T06:26:13.253 回答
2

你有几个解决方案。

  1. 首先,您可以通过设计解决它。创建没有可以修改对象状态的方法的接口。例如,它将仅包含 getter。现在变量类型是接口。客户端将无法修改状态。
  2. 如果你的类实现了接口,你可以使用动态代理来包装它,防止调用 setter。顺便说一句,如果您的班级实际上是集合或地图,您可以使用Collections.unmodifireableMap()Collections.unmodifireableList()使其确实不可修改。
  3. 您可以使用字节码工程。即使您的类没有实现任何接口,这也将起作用。有两种方法可以做到这一点。javassist 和 cglib 等库允许创建包装具体类的动态代理。因此,您可以使用使用这些库之一创建的代理来包装您的对象。调用 setter 时代理会抛出异常。
  4. 在编译时使用字节码修改。例如 AspectJ 可以帮助你。
于 2012-10-29T06:31:31.023 回答
0

另一种选择是创建一个委托,它覆盖所有将更改对象状态的方法,而是抛出异常或执行空操作。

于 2012-10-29T06:28:53.630 回答