有没有办法在java中将对象的值固定为常量?

时间:2012-10-29 06:23:13

标签: java final

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

final Object object = new Object();

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

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

在这种情况下应该是什么功能原型?

4 个答案:

答案 0 :(得分:4)

诀窍是定义对象的只读接口,并将setter只放入类中,如下所示:

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,然后致电设置者。

答案 1 :(得分:3)

  

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

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

答案 2 :(得分:2)

您有多种解决方案。

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

答案 3 :(得分:0)

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