繁体   English   中英

如果我们使用反射更改最终属性值,则不会抛出 UnsupportedEncodingException

[英]UnsupportedEncodingException is not getting thrown, if we change final property value using reflection

package com.java.random.practice;
    
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
    
public class App 
{
    private static final String ENCODING = "\\UTF-8";
    public static void main( String[] args ) throws UnsupportedEncodingException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
        {      
            URLEncoder.encode("anyValue", ENCODING);
        }
}

上面的代码在使用“\”进行编码时会抛出异常UnsupportedEncodingException,但是当我们使用反射来修改值时,它不会显示任何异常,请参见下面的代码:

package com.java.random.practice;
    
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.net.URLEncoder;
    
public class App 
{
    private static final String ENCODING = "UTF-8";
    public static void main( String[] args ) throws UnsupportedEncodingException, NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException
        {      
            App app=new App(); 
            Field field = app.getClass().getDeclaredField("ENCODING");
            field.setAccessible(true); 
            Field modifiersField =
            Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true); modifiersField.setInt(field,
            field.getModifiers() & ~Modifier.FINAL); field.set(null, "\\UTF-8");
             
            String s= URLEncoder.encode("anyValue", ENCODING);
            System.out.println(s);
        }
    }

为什么会有这种奇怪的行为?

编译时间常数的值由编译器内联

这是什么意思?
假设有private static final String STR = "Foo"; . 在这里,我们确定(使用标准语言规则,不包括反射,因为它是一种破坏语言强制执行的所有保证的工具,例如:防止访问private成员、修改final等) STR的值应该始终为"Foo"并且信息在编译时也是已知的。

这允许编译器优化像System.out.println(STR);这样的代码。 并消除了查找STR值的需要,而是直接使用它,这将产生与我们编写System.out.println("Foo"); (因为编译器知道值并且“理论上”总是相同的)。

因此,即使我们使用反射并将新值重新分配给STR ,它也不会影响代表System.out.println("Foo"); 因为它不再依赖于STR

在你的情况下

String s= URLEncoder.encode("anyValue", ENCODING);

将像您将其编写为一样进行编译

String s= URLEncoder.encode("anyValue", "UTF-8");

(因为private static final String ENCODING = "UTF-8"; ENCODINT的值为"UTF-8" ,并且在使用ENCODINT的地方内联)。 因此,即使您为ENCODINT (此处为“\UTF-8”)分配新值,它也不会影响表示URLEncoder.encode("anyValue", "UTF-8")字节码,因为它不使用/参考ENCODING .

如果要防止内联,请不要使ENCODING成为编译时间常数。 换句话说,确保分配的值需要在运行时“计算”。 例如,您可以使用private static final String ENCODING = "UTF-8".substring(0); .

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM