简体   繁体   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);
        }
}

Above code throws exception UnsupportedEncodingException when use "\" with encoding but when we use Reflection to modify the value then it does not show any exception, please see the below code:上面的代码在使用“\”进行编码时会抛出异常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);
        }
    }

Why this kind of strange behavior?为什么会有这种奇怪的行为?

Values of compilation time constants are inlined by compiler.编译时间常数的值由编译器内联

What does it mean?这是什么意思?
Lets say there is private static final String STR = "Foo";假设有private static final String STR = "Foo"; . . Here we are sure (using standard language rules, without including reflection since it is a tool that breaks all guarantees language enforces, like: preventing accessing private members, modifying final , etc.) that value of STR should be always "Foo" and that information is also known at compilation time.在这里,我们确定(使用标准语言规则,不包括反射,因为它是一种破坏语言强制执行的所有保证的工具,例如:防止访问private成员、修改final等) STR的值应该始终为"Foo"并且信息在编译时也是已知的。

This allows compiler to optimize code like System.out.println(STR);这允许编译器优化像System.out.println(STR);这样的代码。 and remove the need to lookup value of STR but instead use it directly which will produce same bytecode as if we would write System.out.println("Foo");并消除了查找STR值的需要,而是直接使用它,这将产生与我们编写System.out.println("Foo"); (since value is known to compiler and "theoretically" always the same). (因为编译器知道值并且“理论上”总是相同的)。

So even if we use reflection and reassign new value to STR it will not affect bytecode which represents System.out.println("Foo");因此,即使我们使用反射并将新值重新分配给STR ,它也不会影响代表System.out.println("Foo"); since it no longer depends on STR .因为它不再依赖于STR

In your case在你的情况下

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

will be compiled as if you would write it as将像您将其编写为一样进行编译

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

(since private static final String ENCODING = "UTF-8"; value of ENCODINT is "UTF-8" and that is inlined in places where ENCODINT is being used). (因为private static final String ENCODING = "UTF-8"; ENCODINT的值为"UTF-8" ,并且在使用ENCODINT的地方内联)。 So even if you assign new value to ENCODINT (here "\UTF-8") it can't affect bytecode which represents URLEncoder.encode("anyValue", "UTF-8") since it doesn't use/refer to ENCODING .因此,即使您为ENCODINT (此处为“\UTF-8”)分配新值,它也不会影响表示URLEncoder.encode("anyValue", "UTF-8")字节码,因为它不使用/参考ENCODING .

If you want to prevent inlining don't make ENCODING a compilation time constant.如果要防止内联,请不要使ENCODING成为编译时间常数。 In other words ensure that assigned value will need to be "calculated" at runtime.换句话说,确保分配的值需要在运行时“计算”。 For instance you can use private static final String ENCODING = "UTF-8".substring(0);例如,您可以使用private static final String ENCODING = "UTF-8".substring(0); . .

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

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