搜尋
首頁Javajava教程Java反射的使用方法及範例分析

    反射

    反射定義

    物件可以透過反射取得他的類,類別可以透過反射拿到所有⽅法(包括私有) 透過java語言中的反射機制可以操作字節碼文件,可以讀取和修改字節碼文件

    #反射的基本運用

    1. 取得類別物件

    a. forName()方法

    只需要知道類別名,在載入JDBC的時候會採用實例代碼

    public class test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Class name = Class.forName("java.lang.Runtime");
            System.out.println(name);
        }
    }

    Java反射的使用方法及範例分析

    b. 直接取得

    使用.class去取得對於的對象

    public class test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> name = Runtime.class;
            System.out.println(name);
        }
    }
    c. getClass()方法

    getClass來取得字節碼對象,必須要明確具體的類,然後建立物件

    public class test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Runtime rt = Runtime.getRuntime();
            Class<?> name = rt.getClass();
            System.out.println(name);
        }
    }
    d. getSystemClassLoader().loadClass()方法

    這個方法和forName類似,只要有類別名稱就可以了,但是差別在於,forName的靜態JVM會裝載類,並執行static()中的代碼

    public class getSystemClassLoader {
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> name = ClassLoader.getSystemClassLoader().loadClass("java.lang.Runtime");
            System.out.println(name);
        }
    }

    2. 取得類別方法

    a. getDeclaredMethods

    傳回類別或介面宣告的所有方法,包括public 、protected、private和預設方法,但不包含繼承的方法

    import java.lang.reflect.Method;
    
    public class getDeclaredMethods {
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> name = Class.forName("java.lang.Runtime");
            System.out.println(name);
            Method[] m = name.getDeclaredMethods();
            for(Method x:m)
                System.out.println(x);
        }
    }

    Java反射的使用方法及範例分析

    #b.getDeclaredMethod

    取得特定的方法,第一個參數是方法名,第二個參數是該方法的參數對應的class對象,例如這裡Runtime的exec方法參數為一個String,所以這裡的第二個參數是String.class

    import java.lang.reflect.Method;
    
    public class getDeclaredMethod {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException {
            Class<?> name = Class.forName("java.lang.Runtime");
            Method m = name.getDeclaredMethod("exec",String.class);
            System.out.println(m);
        }
    }
    c. getMethods

    傳回某個類別所有的public方法,包含繼承類別的public方法

    d. getMethod

    參數同理getDeclaredMethod

    #3. 取得成員變數

    同理Method的那幾個方法

    a. getDeclaredFields

    取得類別的成員的所有變數數組,但是不包括父類別的

    b .getDeclaredField(String name)

    取得特定的,參數是想要的方法的名稱

    c. getFields()

    同理,只能獲得public的,但是包括了父類別的

    d. getField(String name)

    同理,參數是想要的方法的名稱

    4. 取得建構子Constructor

    Constructor>[] getConstructors() :只回傳public建構子

    Constructor>[] getDeclaredConstructors() :傳回所有建構子

    # Constructor getConstructor(類別>... parameterTypes) : 匹配和參數配型相符的public建構子

    Constructor getDeclaredConstructor(類別>... parameterType> getDeclaredConstructor(類別>... parameterType> ) : 匹配和參數配型相符的建構子

    後面兩個方法的參數是對於方法的參數的型別的class對象,和Method的那個類似,例如String.class

    5. 反射創建類別物件

    newInstance

    #可以透過反射來產生實例化對象,一般我們使用Class對象的newInstance()方法來進行建立類別物件

    建立的方法是:只需要透過forname方法取得的class物件中進行newInstance方法建立即可

    Class c = Class.forName("com.reflect.MethodTest"); // 创建Class对象
    Object m1 =  c.newInstance(); // 创建类对象
    invoke

    # invoke方法位於java.lang.reflect.Method類別中,用來執行某個的物件的目標方法,一般會和getMethod方法配合進行呼叫。

    使用用法:

    public Object invoke(Object obj, Object... args)

    第一個參數為類別的實例,第二個參數為對應函數中的參數

    obj:從中呼叫底層方法的對象,必須是實例化物件

    args: 用於方法的調用,是一個object的數組,參數有可能是多個

    但需要注意的是,invoke方法第一個參數並不是固定的:

    • 如果呼叫這個方法是普通方法,第一個參數就是類別物件;

    • ##如果呼叫這個方法是靜態方法,第一個參數就是類別;

    透過一個例子去理解

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Invoke {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
            Class c = Class.forName("Invoke");
            Object o = c.newInstance();
            Method m = c.getMethod("test");
            m.invoke(o);
        }
        public void test(){
            System.out.println("测试成功");
        }
    }

    Java反射的使用方法及範例分析

    簡單來說就是這樣

    方法.invoke(類別或類別物件)

    先forName拿到Class,再newInstance取得類別對象,再getMethod取得方法,然後呼叫

    Runtime的rce範例(存取限制突破)

    Runtime類別裡面有一個exec方法,可以執行指令

    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Exec {
        public static void main(String[] args) throws ClassNotFoundException, InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
            Class c = Class.forName("java.lang.Runtime");
            Object o = c.newInstance();
            Method m = c.getMethod("exec",String.class);
            m.invoke(o,"/System/Applications/Calculator.app/Contents/MacOS/Calculator");
        }
    }

    但是發現報錯了

    Java反射的使用方法及範例分析

    出現這個問題的原因:

    • 使用的類別沒有無參考建構子

    • 使用的類別建構子是私有的

    那麼解決方案就是

    setAccessible(true);,用這個去突破存取限制

    Java.lang.reflect.AccessibleObject类是Field,Method和Constructor类对象的基类,可以提供将反射对象标记为使用它抑制摸人Java访问控制检查的功能,同时上述的反射类中的Field,Method和Constructor继承自AccessibleObject。所以我们在这些类方法基础上调用setAccessible()方法,既可对这些私有字段进行操作

    简单来说,私有的属性、方法、构造方法,可以通过这个去突破限制,xxx.setAccessible(true) 可以看到Runtime的构造方法是private的

    Java反射的使用方法及範例分析

    那么这里我们就可以这么去突破限制 先获取构造方法,然后setAccessible获取访问权限 然后再最后invoke里面,第一个参数写成con.newInstance()

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Exec {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
            Class c = Class.forName("java.lang.Runtime");
            Constructor con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Method m = c.getMethod("exec",String.class);
            m.invoke(con.newInstance(),"/System/Applications/Calculator.app/Contents/MacOS/Calculator");
        }
    }

    Java反射的使用方法及範例分析

    这里有一个疑问,如果把con.newInstance单独提取出来,他打开计算器不会显示出来,但是后台的确是启动了,不知道啥原因

    import java.lang.reflect.Constructor;
    import java.lang.reflect.InvocationTargetException;
    import java.lang.reflect.Method;
    
    public class Exec {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, InstantiationException {
            Class c = Class.forName("java.lang.Runtime");
            Constructor con = c.getDeclaredConstructor();
            con.setAccessible(true);
            Object o = con.newInstance();
            Method m = c.getMethod("exec",String.class);
            m.invoke(o,"/System/Applications/Calculator.app/Contents/MacOS/Calculator");
        }
    }

    后记

    反射中常用的几个重要方法:

    • 获取类的⽅法: forName

    • 实例化类对象的⽅法: newInstance

    • 获取函数的⽅法: getMethod

    • 执⾏函数的⽅法: invoke

    • 限制突破方法:setAccessible

    以上是Java反射的使用方法及範例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
    如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?如何將Maven或Gradle用於高級Java項目管理,構建自動化和依賴性解決方案?Mar 17, 2025 pm 05:46 PM

    本文討論了使用Maven和Gradle進行Java項目管理,構建自動化和依賴性解決方案,以比較其方法和優化策略。

    如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?如何使用適當的版本控制和依賴項管理創建和使用自定義Java庫(JAR文件)?Mar 17, 2025 pm 05:45 PM

    本文使用Maven和Gradle之類的工具討論了具有適當的版本控制和依賴關係管理的自定義Java庫(JAR文件)的創建和使用。

    如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?如何使用咖啡因或Guava Cache等庫在Java應用程序中實現多層緩存?Mar 17, 2025 pm 05:44 PM

    本文討論了使用咖啡因和Guava緩存在Java中實施多層緩存以提高應用程序性能。它涵蓋設置,集成和績效優勢,以及配置和驅逐政策管理最佳PRA

    如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?如何將JPA(Java持久性API)用於具有高級功能(例如緩存和懶惰加載)的對象相關映射?Mar 17, 2025 pm 05:43 PM

    本文討論了使用JPA進行對象相關映射,並具有高級功能,例如緩存和懶惰加載。它涵蓋了設置,實體映射和優化性能的最佳實踐,同時突出潛在的陷阱。[159個字符]

    Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Java的類負載機制如何起作用,包括不同的類載荷及其委託模型?Mar 17, 2025 pm 05:35 PM

    Java的類上載涉及使用帶有引導,擴展程序和應用程序類負載器的分層系統加載,鏈接和初始化類。父代授權模型確保首先加載核心類別,從而影響自定義類LOA

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    4 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    4 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您聽不到任何人,如何修復音頻
    1 個月前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.聊天命令以及如何使用它們
    1 個月前By尊渡假赌尊渡假赌尊渡假赌

    熱工具

    WebStorm Mac版

    WebStorm Mac版

    好用的JavaScript開發工具

    EditPlus 中文破解版

    EditPlus 中文破解版

    體積小,語法高亮,不支援程式碼提示功能

    Dreamweaver Mac版

    Dreamweaver Mac版

    視覺化網頁開發工具

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    SAP NetWeaver Server Adapter for Eclipse

    SAP NetWeaver Server Adapter for Eclipse

    將Eclipse與SAP NetWeaver應用伺服器整合。