Java中的最终变量操作
有谁能告诉我以下这行在Java环境中的含义是什么 最后一个变量仍然可以是 除非它是不可变的Java中的最终变量操作,java,variables,final,Java,Variables,Final,有谁能告诉我以下这行在Java环境中的含义是什么 最后一个变量仍然可以是 除非它是不可变的 据我所知,通过将任何变量声明为final,您不能再次更改它,那么上面一行中单词immutable的含义是什么?如果您对Java对象有最终引用,您仍然可以操作它,但不能更改它的引用。例如,此代码完全合法: import javax.swing.JLabel; class Test1 { private final static JLabel l = new JLabel("Old text");
据我所知,通过将任何变量声明为final,您不能再次更改它,那么上面一行中单词immutable的含义是什么?如果您对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());
}
}
但你不能说:
l = new JLabel("Newest Text");
在第一次分配到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());
}
}
这是可以做到的,因为当l被声明时,它并没有被赋值给任何非空的东西。所以你只能给它分配一次
原语也是如此。可以按如下方式为其指定值:
class Test1 {
public static void main(String[] args) {
final int i;
i = 2;
}
}
但是现在您无法进一步操作它,因为您可以对基元类型执行的唯一操作就是为它们赋值。您仍然可以使用反射更改“final”变量。这意味着,如果您的最终变量是引用类型(即不是像int一样的基元),那么它只是不能更改的引用。不能使它引用其他对象,但是如果类允许,它引用的对象的字段仍然可以更改。例如:
final StringBuffer s = new StringBuffer();
StringBuffer的内容仍然可以任意更改:
s.append("something");
但你不能说:
s = null;
或
另一方面:
final String s = "";
字符串是不可变的-根本没有任何方法可以让您更改字符串(除非您使用反射-见鬼去吧)。正如其他人所说,这意味着您可以操作变量指向的对象,但您不能更改引用(即为变量指定另一个对象)
可通过设计更改的对象,如
列表
,可以更改(您可以向其添加元素),而如果您有一个不可变的对象,如字符串
或整数
,则无法更改它(类字符串支持的所有操作都返回一个新实例,并且不修改实际对象)。不能更改最终变量引用的对象或值。只能分配一次最终变量
这对您是否可以更改对象的状态没有影响。除非以禁止此操作的方式对对象本身进行编码,否则仍然可以对其进行操作。不可变对象是状态无法更改的对象。您可以对其调用任何方法,即使该方法可以更改引用对象的状态指的是
final MyClass myClass = new MyClass();
myClass.setVar(something);
这很好,因为myClass
本身没有改变,也就是说,你没有做总是让我丧命的myClass=myClass1;
如果您希望最终变量实际上像您认为的那样安全,则需要大量额外的代码来返回字符串[]的副本。您可以为StringBuffer类型等操作可变的最终变量,但无法操作不可变类型的最终变量。
如果是可变变量,则不会在每次更改其值时都创建新对象。但是如果是不可变类型,则无论何时更改值,都会创建新对象,因此当您将其设置为最终值时,您无法对其进行修改。是,可以修改最终变量
final StringBuffer s = new StringBuffer();
// won't work
s = new StringBuffer();
//this works
s.append("hai");
您不能更改引用,但可以修改对象的字段。以下是我几年前创建的代码,用于关闭final,然后再打开,以便您可以修改引用/值,它只对变量有效,但确实有效
您也可以对方法句柄执行类似的操作,但是,除非您正在编写某种形式的自动对象解析器/生成器,否则我将避免像瘟疫一样执行这两种操作
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);
}
}
}
publicstaticvoidsetvalueonfield(对象实例、字段、对象值)
抛出NoSuchFieldException、IOException、IllegalArgumentException、,
非法访问例外{
try(访问器访问=打开(字段)){
field.set(实例、值);
}
}
公共静态类访问器
可关闭的机具{
私有最终布尔值是可访问的;
私有final布尔值是final;
私有final int修饰符;
私有最终可访问对象;
私有访问器(T accessibleObject)引发IOException{
超级();
if(accessibleObject==null){
抛出新IOException(
“为可访问性准备字段时出错:字段为空”);
}
试一试{
this.accessibleObject=accessibleObject;
this.modifiers=accessibleObject.getModifiers();
this.isAccessible=accessibleObject.isAccessible();
this.isFinal=修饰符.isFinal(修饰符);
如果(!this.isAccessible){
accessibleObject.setAccessible(true);
}
如果(此.isFinal){
getModifiersField(accessibleObject).setInt(
accessibleObject、修饰符&~Modifier.FINAL);
}
}捕获(例外e){
抛出新IOException(“准备可访问性字段时出错”,
e) );
}
}
@凌驾
public void close()引发IOException{
如果(!this.isAccessible){
accessibleObject.setAccessible(false);
}
如果(此.isFinal){
试一试{
getModifiersField(accessibleObject).setInt(
可访问对象、修改器);
}捕获(例外e){
抛出新IOException(“将字段设置为最终错误”,e);
}
}
}
公共T getAccessibleObject(){
返回可访问对象;
}
专用静态场
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);
}
}
}