Java中的最终变量操作
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1249917/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Final variable manipulation in Java
提问by Dusk
Could anyone please tell me what is the meaning of the following line in context of Java:
谁能告诉我以下行在 Java 上下文中的含义是什么:
final variable can still be manipulated unless it's immutable
final 变量仍然可以被操纵,除非它是不可变的
As far as I know, by declaring any variable as final, you can't change it again, then what they mean with the word immutablein above line?
据我所知,通过将任何变量声明为最终变量,您无法再次更改它,那么上面一行中的不可变一词是什么意思?
采纳答案by Michael Borgwardt
It means that if your final variable is a reference type (i.e. not a primitive like int), then it's only the reference that cannot be changed. It cannot be made to refer to a different object, but the fields of the object it refers to can still be changed, if the class allows it. For example:
这意味着如果你的最终变量是一个引用类型(即不是像 int 这样的原语),那么它只是不能改变的引用。它不能引用不同的对象,但如果类允许,它引用的对象的字段仍然可以更改。例如:
final StringBuffer s = new StringBuffer();
The content of the StringBuffer can still be changed arbitrarily:
StringBuffer 的内容仍然可以任意更改:
s.append("something");
But you cannot say:
但你不能说:
s = null;
or
或者
s = anotherBuffer;
On the other hand:
另一方面:
final String s = "";
Strings are immutable - there simply isn't any method that would enable you to change a String (unless you use Reflection - and go to hell).
字符串是不可变的 - 根本没有任何方法可以让您更改字符串(除非您使用反射 - 并且见鬼去吧)。
回答by Savvas Dalkitsis
If you have a final reference to a Java object you can still manipulate it but cannot change its reference. For instance this code is perfectly legal:
如果您有对 Java 对象的最终引用,您仍然可以操作它,但不能更改它的引用。例如,这段代码是完全合法的:
import javax.swing.JLabel;
class Test1 {
private final static JLabel l = new JLabel("Old text");
public static void main(String[] args) {
System.err.println(l.getText());
l.setText("New Text");
System.err.println(l.getText());
}
}
But you can't say:
但你不能说:
l = new JLabel("Newest Text");
After the first assignment to l. Note that you can do this though:
第一次赋值给l后。请注意,您可以这样做:
import javax.swing.JLabel;
class Test1 {
public static void main(String[] args) {
final JLabel l;
String s = getArbitaryString(); // Assume this method returns a string
l = new JLabel(s);
System.err.println(l.getText());
}
}
This can be done because when l is declared it is not assigned to anything not even null. So you are allowed to assign something to it one time only.
这是可以做到的,因为当 l 被声明时,它没有被分配给任何不为空的东西。所以你只能给它分配一次。
Same thing goes for primitives. You can assign a value to it like this:
同样的事情也适用于原语。您可以像这样为它分配一个值:
class Test1 {
public static void main(String[] args) {
final int i;
i = 2;
}
}
But now you cannot manipulate it further since the only thing you can do to primitive types is to assign values to them.
但是现在您无法进一步操作它,因为您可以对原始类型做的唯一事情就是为它们分配值。
回答by Javamann
You can still change a 'final' variable using Reflection.
您仍然可以使用反射更改“最终”变量。
回答by pgb
As others have said, it means that you can manipulate the object the variable points at, but you cannot change the reference (i.e. assign another object to the variable).
正如其他人所说,这意味着您可以操作变量指向的对象,但不能更改引用(即将另一个对象分配给变量)。
Objects that are mutable by design, such as a List
can be changed (you can add elements to them) whereas if you have an immutable object such as a String
or Integer
you won't be able to change it (all the operations the class String
supports return a new instance, and don't modify the actual object).
设计上可变的对象,例如 aList
可以更改(您可以向它们添加元素),而如果您有一个不可变对象,例如 aString
或者Integer
您将无法更改它(该类String
支持的所有操作都返回 a新实例,并且不要修改实际对象)。
回答by Fred
You cannot change what object or value a final variable refers to. You can only assign a final variable once.
您不能更改最终变量引用的对象或值。您只能分配一个最终变量一次。
This has no effect on whether you can change the state of the object. The object itself can still be manipulated unless it is coded in such a way that this manipulation is forbidden. An immutable object is an object whose state cannot change.
这对您是否可以更改对象的状态没有影响。对象本身仍然可以被操纵,除非它以禁止这种操纵的方式进行编码。不可变对象是状态不能改变的对象。
回答by fastcodejava
You can call any method on it even if the method can change the state of the object the reference is pointing to. E.g
即使该方法可以更改引用指向的对象的状态,您也可以对其调用任何方法。例如
final MyClass myClass = new MyClass();
myClass.setVar(something);
This is fine because myClass
itself is not changing, i.e you are not doing myClass = myClass1;
.
这很好,因为myClass
它本身并没有改变,即你没有在做myClass = myClass1;
。
回答by Dean J
The one that always kills me?
那个总是杀了我的人?
If you want final variables to actually be as safe as you thought they were, you need a lot of extra code to return a copy of a String[].
如果您希望最终变量真正像您想象的那样安全,您需要大量额外的代码来返回 String[] 的副本。
回答by deepakraut
You can manipulate mutable final variables for e.g. of type StringBuffer but you cannot manipulate final variables of immutable types.
您可以操作例如 StringBuffer 类型的可变最终变量,但您不能操作不可变类型的最终变量。
In case of mutable variables, new object is not created every time it's value is changed. But in case of of immutable types, whenever you change value, new object is created, so when you make it final, you cannot modify it.
对于可变变量,每次更改其值时都不会创建新对象。但是对于不可变类型,每当您更改值时,都会创建新对象,因此当您将其设为 final 时,您无法修改它。
回答by vaisakh ps
Yes the final variable can be modified.
是的,可以修改最终变量。
final StringBuffer s = new StringBuffer();
// won't work
s = new StringBuffer();
//this works
s.append("hai");
You can't change the reference but the fields of the the object can be modified. for more details
您不能更改引用,但可以修改对象的字段。更多细节
回答by Hyman Moxley
The following is code I created several years back to turn final off and then back on so you can modify the reference/value, it will only work on variables, but it does work.
以下是我几年前创建的代码,用于关闭最终关闭然后重新打开,以便您可以修改引用/值,它仅适用于变量,但确实有效。
You can also do something similar with method handles, however unless you are writing some form of auto object parser/generator, I would avoid doing either like the plague.
你也可以用方法句柄做类似的事情,但是除非你正在编写某种形式的自动对象解析器/生成器,否则我会避免像瘟疫那样做。
public static void setValueOnField(Object instance, Field field, Object value)
throws NoSuchFieldException, IOException, IllegalArgumentException,
IllegalAccessException {
try (Accessor<Field> access = open(field)) {
field.set(instance, value);
}
}
public static class Accessor<T extends AccessibleObject & Member>
implements Closeable {
private final boolean isAccessible;
private final boolean isFinal;
private final int modifiers;
private final T accessibleObject;
private Accessor(T accessibleObject) throws IOException {
super();
if (accessibleObject == null) {
throw new IOException(
"Error preparing field for accesibility: Field is null");
}
try {
this.accessibleObject = accessibleObject;
this.modifiers = accessibleObject.getModifiers();
this.isAccessible = accessibleObject.isAccessible();
this.isFinal = Modifier.isFinal(modifiers);
if (!this.isAccessible) {
accessibleObject.setAccessible(true);
}
if (this.isFinal) {
getModifiersField(accessibleObject).setInt(
accessibleObject, modifiers & ~Modifier.FINAL);
}
} catch (Exception e) {
throw new IOException("Error preparing field for accesibility",
e);
}
}
@Override
public void close() throws IOException {
if (!this.isAccessible) {
accessibleObject.setAccessible(false);
}
if (this.isFinal) {
try {
getModifiersField(accessibleObject).setInt(
accessibleObject, modifiers);
} catch (Exception e) {
throw new IOException("Error setting field to final", e);
}
}
}
public T getAccessibleObject() {
return accessibleObject;
}
private static Field getModifiersField(AccessibleObject toFetch) {
Field field;
try {
field = toFetch.getClass().getField("modifiers");
field.setAccessible(true);
return field;
} catch (Exception e) {
throw new RuntimeException(
"Error occured getting modifiers field", e);
}
}
}