簡體   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