使用反射修改final修饰的属性

使用反射修改final修饰的属性

先给个例子

public class FinalClass {
    private final int intValue = 1;							//编译前赋值的基础类型
    private final Integer integerValue = new Integer(1);	//基础类型的包装类
    private final int noValueInt;							//运行时赋值的基础类型

    private final String literalString = "1";				//编译前赋值的LiteralString
    private final String newString = new String("1");		//new关键字建的String对象
    private final String noValueString;						//运行时赋值的String对象

    public int getIntValue() {
        return intValue;
    }

    public Integer getIntegerValue() {
        return integerValue;
    }

    public String getLiteralString() {
        return literalString;
    }

    public String getNewString() {
        return newString;
    }

    public int getNoValueInt() {
        return noValueInt;
    }

    public String getNoValueString() {
        return noValueString;
    }

    public FinalClass(int noValueInt, String noValueString) {
        this.noValueInt = noValueInt;
        this.noValueString = noValueString;
    }
}

然后用反射试着修改一下属性值

public static void modify(Object object, String fieldName, Object newFieldValue) throws Exception {
    Field field = object.getClass().getDeclaredField(fieldName);

    Field modifiersField = Field.class.getDeclaredField("modifiers");
    modifiersField.setAccessible(true);
    modifiersField.setInt(field, field.getModifiers() & ~Modifier.FINAL);

    if(!field.isAccessible()) {
        field.setAccessible(true);
    }

    field.set(object, newFieldValue);
}

public static void main(String[] args) throws Exception {
    FinalClass finalClass = new FinalClass(1, "1");
    modify(finalClass, "intValue", 2);
    modify(finalClass, "integerValue", 2);
    modify(finalClass, "noValueInt", 2);
    modify(finalClass, "literalString", "2");
    modify(finalClass, "newString", "2");
    modify(finalClass, "noValueString", "2");

    System.out.println(finalClass.getIntValue());           //1
    System.out.println(finalClass.getIntegerValue());       //2
    System.out.println(finalClass.getNoValueInt());         //2
    System.out.println(finalClass.getLiteralString());      //1
    System.out.println(finalClass.getNewString());          //2
    System.out.println(finalClass.getNoValueString());      //2
}

虽然代码顺利的执行了,并没有报错,但是有一些属性值似乎没有被修改,那么是不是真的没有被修改呢,我们用反射再看一下所有的属性值。

Field[] fields = finalClass.getClass().getDeclaredFields();
for (Field field : fields){
    field.setAccessible(true);
    System.out.println(field.get(finalClass));  //2
}

可以看到,所有的都被修改了,那么为什么有些属性我们调用get方法后得到的返回值仍然为1呢。我们看一下反编译后的代码。

public class FinalClass {
    private final int intValue = 1;
    private final Integer integerValue = new Integer(1);
    private final int noValueInt;
    private final String literalString = "1";
    private final String newString = new String("1");
    private final String noValueString;

    public int getIntValue() {
        return 1;
    }

    public Integer getIntegerValue() {
        return this.integerValue;
    }

    public String getLiteralString() {
        return "1";
    }

    public String getNewString() {
        return this.newString;
    }

    public int getNoValueInt() {
        return this.noValueInt;
    }

    public String getNoValueString() {
        return this.noValueString;
    }

    public FinalClass(int var1, String var2) {
        this.noValueInt = var1;
        this.noValueString = var2;
    }
}

这个时候就很明显了, Java 编译器对 final 属型进行了内联优化,即编译时把该 final 属性的值直接放到了引用它的地方。即使是反射修改了该属性,但是引用它的地方放的并不是属性引用而是属性值,所以返回值并没有变。

但是 Java 编译器不会对所有的 final 属型进行内联优化,只有八种基本类型属性和 LiteralString(直接用引号包裹而不是new关键字实例化的字符串) 会进行内联优化,对于引用类型不会则进行内联优化。此外,在运行期间才确定值的final属性也不会进行内联优化。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值