在 Java 中在运行时添加 final 修饰符
Add final modifier at runtime in Java
听起来可能有点奇怪,但是可以在运行时添加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
At certain point I want to prevent changing its value
在应用程序逻辑中这样做。使变量只能通过方法访问。保留一个标记来跟踪对变量的任何更改。在您应用更改或达到 特定点 后,升起标志,并为任何进一步更改变量的尝试抛出异常。
final
是一种语言 keyword/feature,用于编写源代码并防止在源代码中重新分配变量。在运行时,它(几乎)什么都不做。
使用不可变对象:
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
如果您在想,"But then they can still modify the value by replacing the object!"当然可以。防止这种情况的唯一方法是锁定某些全局状态(如果它不是常量,这实际上是不可能的),但您没有使用全局状态,对吗?全局状态是一件坏事TM.
全局状态有一个非常简单的问题:它使您的代码的可重用性大大降低并且更容易出错。如果您在运行时修改该全局状态,则尤其容易出错。 "Aw, crap, things are happening in the wrong order." 你不知道这有多么容易。试图跟踪事件的顺序是多线程如此困难的原因。就可重用性而言,这意味着你不能拥有事物的两个独立实例,这反过来意味着你不能真正拥有依赖于它的任何事物的任何两个实例(至少当事实证明你需要改变时)毕竟这件事)。
即使这不是全局的,这也是一种奇怪的状态,每个必须修改您的代码的人(包括您自己)在进行更改时都必须了解并考虑。这听起来像是会让改变变得更容易还是更难? (提示:后者。)不要对自己或同事这样做。让它更简单。吸取教训Zen of Python:"Simple is better than complex."
所以底线是:如果您需要不可变对象,请使用不可变对象。如果您需要一个不是常量的不可变全局变量,请想出一种更好的方法来组织您的代码。
听起来可能有点奇怪,但是可以在运行时添加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
At certain point I want to prevent changing its value
在应用程序逻辑中这样做。使变量只能通过方法访问。保留一个标记来跟踪对变量的任何更改。在您应用更改或达到 特定点 后,升起标志,并为任何进一步更改变量的尝试抛出异常。
final
是一种语言 keyword/feature,用于编写源代码并防止在源代码中重新分配变量。在运行时,它(几乎)什么都不做。
使用不可变对象:
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
如果您在想,"But then they can still modify the value by replacing the object!"当然可以。防止这种情况的唯一方法是锁定某些全局状态(如果它不是常量,这实际上是不可能的),但您没有使用全局状态,对吗?全局状态是一件坏事TM.
全局状态有一个非常简单的问题:它使您的代码的可重用性大大降低并且更容易出错。如果您在运行时修改该全局状态,则尤其容易出错。 "Aw, crap, things are happening in the wrong order." 你不知道这有多么容易。试图跟踪事件的顺序是多线程如此困难的原因。就可重用性而言,这意味着你不能拥有事物的两个独立实例,这反过来意味着你不能真正拥有依赖于它的任何事物的任何两个实例(至少当事实证明你需要改变时)毕竟这件事)。
即使这不是全局的,这也是一种奇怪的状态,每个必须修改您的代码的人(包括您自己)在进行更改时都必须了解并考虑。这听起来像是会让改变变得更容易还是更难? (提示:后者。)不要对自己或同事这样做。让它更简单。吸取教训Zen of Python:"Simple is better than complex."
所以底线是:如果您需要不可变对象,请使用不可变对象。如果您需要一个不是常量的不可变全局变量,请想出一种更好的方法来组织您的代码。