在 Java 中运行时添加最终修饰符

2022-09-02 20:28:22

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

我有一个标记为.在某些时候,我想防止更改其值,并且我希望将其可访问性保持为标准的静态值()。public static int/shortClassName.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

答案 1

在某一点上,我想防止改变它的值

在应用程序逻辑中执行此操作。使变量只能通过方法访问。保留一个标志来跟踪对变量的任何更改。应用更改或达到某个点后,请升起标志,并为更改变量的任何进一步尝试引发异常。

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


答案 2

使用不可变对象:

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

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

即使这不是全局的,那么这是一些奇怪的状态,每个必须修改代码的人(包括你自己)都必须在进行更改时意识到并考虑。这听起来像是会让改变事情变得更容易还是更难?(提示:后者。不要对自己或同事这样做。让它更简单。从Python的禅宗中吸取教训:“简单比复杂好。

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


推荐