在Java中运行时添加final修饰符

时间:2015-01-16 19:21:08

标签: java final modifier

听起来有点奇怪,但可以在运行时添加final修饰符吗?

我有一个标记为public static int/short的变量。在某些时候,我想阻止更改其值,并且我希望将其可访问性保持为标准静态值(ClassName.field)。

public class Main {

    private static int a = 0;

    public static void addFinalMod(Field f) {

        Field modifiersField = null;
        try {
            modifiersField = Field.class.getDeclaredField("modifiers");
        }
        catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        modifiersField.setAccessible(true);
        try {
            modifiersField.setInt(f, f.getModifiers() & Modifier.FINAL);
        }
        catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {

        System.out.println(a);
        try {
            Field f = Main.class.getDeclaredField("a");
            addFinalMod(f);
        }
        catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
        a = 10; //I was expecting error/exception here
        System.out.println(a);
    }

输出:

0
10

2 个答案:

答案 0 :(得分:32)

  

在某些时候我想阻止改变它的价值

在应用程序逻辑中执行此操作。使变量只能通过方法访问。保持一个标志跟踪变量的任何变化。应用更改或到达特定点后,请提高标志,并在更改变量的任何进一步尝试时抛出异常。

final是一种语言关键字/功能,用于编写源代码并防止在源代码中重新分配变量。在运行时,它(几乎)没有。

答案 1 :(得分:1)

使用不可变对象:

public class Thing {
    private int value;
    public Thing(int value) { this.value = value; }
    public int getValue() { return this.value; }
}

然后在需要修改时更换它:

Thing x = Thing(1);
// do some stuff
x = Thing(2);
// more stuff

如果你正在思考,"但是他们仍然可以通过替换对象来修改价值!"嗯,当然。防止这种情况的唯一方法是锁定一些全局状态(如果它不是常数,实际上是不可能的),但是你没有使用全局状态,对吧?全球状态是坏事 TM

全局状态有一个非常简单的问题:它使您的代码更不可重用且更容易出错。如果您在运行时修改该全局状态,则容易出错。 "噢,废话,事情发生在错误的顺序。"你不知道这有多容易。试图跟踪事件的顺序是多线程如此困难的原因。就可重用性而言,这意味着你不能拥有两个独立的事物实例,这反过来意味着你不能真正拥有依赖于它的任何事物的任何两个实例(至少当它结果出来时)毕竟你需要改变这个东西。

即使这不是一个全球性的,那么这是一个奇怪的状态,每个必须修改你的代码(包括你自己)的人都必须在他们做出改变时意识到并思考。听起来这会让事情变得更容易或更难吗? (提示:后者。)不要对自己或同事这样做。让它更简单。从Zen of Python中吸取教训:"简单比复杂更好。"

所以底线:如果你需要一个不可变对象,请使用一个不可变对象。如果您需要一个不可变的全局变量,那么找出一种更好的方法来组织您的代码。