Heim  >  Artikel  >  Java  >  Verwendung von Java-Reflexion und Analyse von Beispielen

Verwendung von Java-Reflexion und Analyse von Beispielen

WBOY
WBOYnach vorne
2023-05-06 16:31:08540Durchsuche

    Reflexion

    Reflexionsdefinition

    Objekte können ihre Klassen durch Reflexion erhalten, und Klassen können dies Alle Methoden (einschließlich private) können durch Reflektion erhalten werden, indem Bytecode-Dateien in der Java-Sprache bearbeitet und Bytecode-Dateien gelesen und geändert werden 🎜## 🎜🎜#1. Holen Sie sich das Klassenobjekt

    a. forName()-Methode

    Sie müssen nur den Klassennamen kennen, dann wird der Beispielcode verwendet beim Laden von JDBC

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

    b. Direkt abrufen

    Verwendung von Java-Reflexion und Analyse von BeispielenVerwenden Sie .class, um das Objekt abzurufen

    public class test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Class<?> name = Runtime.class;
            System.out.println(name);
        }
    }
    #🎜 🎜#c getClass()-Methode
    getClass Um das Bytecode-Objekt abzurufen, müssen Sie die spezifische Klasse angeben und dann das Objekt erstellen

    public class test1 {
        public static void main(String[] args) throws ClassNotFoundException {
            Runtime rt = Runtime.getRuntime();
            Class<?> name = rt.getClass();
            System.out.println(name);
        }
    }
    .class去获取对于的对象

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

    getClass来获取字节码对象,必须要明确具体的类,然后创建对象

    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);
        }
    }
    d. getSystemClassLoader().loadClass()方法

    这个方法和forName类似,只要有类名就可以了,但是区别在于,forName的静态JVM会装载类,并执行static()中的代码

    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);
        }
    }

    2. 获取类方法

    a. getDeclaredMethods

    返回类或接口声明的所有方法,包括public、protected、private和默认方法,但是不包括继承的方法

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

    Verwendung von Java-Reflexion und Analyse von Beispielen

    b. getDeclaredMethod

    获取特定的方法,第一个参数是方法名,第二个参数是该方法的参数对应的class对象,例如这里Runtime的exec方法参数为一个String,所以这里的第二个参数是String.class

    public Object invoke(Object obj, Object... args)
    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(类>... parameterTypes) : 匹配和参数配型相符的构造函数

    后面两个方法的参数是对于方法的参数的类型的class对象,和Method的那个类似,例如String.class

    5. 反射创建类对象

    newInstance

    可以通过反射来生成实例化对象,一般我们使用Class对象的newInstance()方法来进行创建类对象

    创建的方法就是:只需要通过forname方法获取到的class对象中进行newInstance方法创建即可

    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("测试成功");
        }
    }
    invoke

    invoke方法位于java.lang.reflect.Method类中,用于执行某个的对象的目标方法,一般会和getMethod方法配合进行调用。

    使用用法:

    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");
        }
    }

    第一个参数为类的实例,第二个参数为相应函数中的参数

    obj:从中调用底层方法的对象,必须是实例化对象

    args: 用于方法的调用,是一个object的数组,参数有可能是多个

    但需要注意的是,invoke方法第一个参数并不是固定的:

    • 如果调用这个方法是普通方法,第一个参数就是类对象;

    • 如果调用这个方法是静态方法,第一个参数就是类;

    通过一个例子去理解

    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");
        }
    }

    Verwendung von Java-Reflexion und Analyse von Beispielen

    简单来说就是这样

    方法.invoke(类或类对象)

    先forName拿到Class,再newInstance获取类对象,再getMethod获取方法,然后调用

    Runtime的rce例子(访问限制突破)

    Runtime类里面有一个exec方法,可以执行命令

    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");
        }
    }

    但是发现报错了

    Verwendung von Java-Reflexion und Analyse von Beispielen

    出现这个问题的原因:

    • 使用的类没有无参构造函数

    • 使用的类构造函数是私有的

    那么解决方案就是setAccessible(true); d. Methode getSystemClassLoader().loadClass()

    #🎜🎜#Diese Methode ähnelt forName, solange es einen Klassennamen gibt, aber der Unterschied besteht darin, dass die statische JVM von forName die Klasse lädt und ausführt der Code in static()#🎜🎜#rrreee #🎜🎜#2. Klassenmethoden abrufen#🎜🎜##🎜🎜#a. getDeclaredMethods#🎜🎜##🎜🎜#Gibt alle von der Klasse oder Schnittstelle deklarierten Methoden zurück, einschließlich öffentliche, geschützte, private und Standardmethoden, jedoch nicht die geerbte Methode#🎜🎜#rrreee#🎜🎜#Beispielanalyse einer Java-Reflexionsanwendungsmethode#🎜🎜##🎜🎜#b. getDeclaredMethod#🎜🎜##🎜🎜#Eine bestimmte Methode abrufen. Der erste Parameter ist der Methodenname und der zweite Parameter ist das Klassenobjekt, das dem Parameter der Methode entspricht. Der exec-Methodenparameter von Runtime ist hier also ein String, daher ist der zweite Parameter hier String.class#🎜🎜#rrreee#🎜🎜#c 🎜##🎜🎜#Gibt alle öffentlichen Methoden einer Klasse zurück, einschließlich öffentlicher Methoden geerbter Klassen#🎜🎜##🎜🎜#d. getMethod#🎜🎜##🎜🎜#Die Parameter sind die gleichen wie getDeclaredMethod#🎜🎜# #🎜🎜#3. Mitgliedsvariablen abrufen#🎜🎜##🎜🎜 #Ähnlich den Methoden von Methode#🎜🎜##🎜🎜#a. getDeclaredFields#🎜🎜##🎜🎜#Ruft alle Variablenarrays von Mitgliedern ab Klasse, enthält jedoch nicht den #🎜🎜##🎜🎜 #b. getDeclaredField(String name)#🎜🎜##🎜🎜#Einen bestimmten Parameter abrufen ist der Name der gewünschten Methode#🎜🎜##🎜 🎜#c. getFields()#🎜🎜##🎜🎜#Wie bei Reason können Sie nur die öffentlichen abrufen, aber die übergeordnete Klasse #🎜🎜##🎜🎜#d einschließen ##🎜🎜#Ebenso ist der Parameter der Name der gewünschten Methode#🎜 🎜##🎜🎜#4. Holen Sie sich den Konstruktor Constructor#🎜🎜#
    #🎜🎜#Constructor>[] getConstructors( ): Gibt nur den öffentlichen Konstruktor zurück. . parameterTypes): Entspricht öffentlichen Konstruktoren, die dem Parametertyp#🎜 🎜##🎜🎜#Constructor getDeclaredConstructor(class>...) entsprechen. ParameterTypes): Entspricht dem Konstruktor, der dem Parametertyp#🎜🎜##🎜🎜#Die letzten beiden Methoden Der Parameter ist ein Klassenobjekt vom Typ des Methodenparameters, ähnlich dem von Methode, wie zum Beispiel String.class#🎜🎜##🎜 🎜#5. Klassenobjekt durch Reflektion erstellen#🎜🎜##🎜🎜 #newInstance#🎜🎜##🎜🎜# Instanziierte Objekte können durch Reflektion generiert werden des Klassenobjekts zum Erstellen von Klassenobjekten #🎜🎜##🎜🎜#Erstellung Die Methode lautet: Sie müssen nur die newInstance-Methode in dem Klassenobjekt erstellen, das über die forname-Methode erhalten wurde #🎜🎜#rrreee#🎜🎜#invoke#🎜 🎜##🎜🎜#invoke-Methode befindet sich in der Klasse java.lang.reflect.Method. Die zum Ausführen eines bestimmten Objekts verwendete Zielmethode wird im Allgemeinen in Verbindung mit der getMethod-Methode aufgerufen. #🎜🎜##🎜🎜#Verwendung: #🎜🎜#rrreee#🎜🎜#Der erste Parameter ist die Instanz der Klasse, der zweite Parameter ist der Parameter in der entsprechenden Funktion #🎜🎜##🎜🎜#obj: from Das Objekt, das die zugrunde liegende Methode aufruft, muss ein instanziiertes Objekt sein muss aufpassen Interessant ist, dass der erste Parameter der Aufrufmethode nicht festgelegt ist: #🎜🎜#
    • #🎜🎜#Wenn diese Methode wie gewohnt aufgerufen wird Methode, der erste Parameter ist das Klassenobjekt; #🎜🎜#
    • #🎜🎜#Wenn der Aufruf dieser Methode eine statische Methode ist, ist der erste Parameter die Klasse; 🎜##🎜🎜#Pass Ein Beispiel zum Verstehen #🎜🎜#rrreee#🎜🎜#So verwenden Sie Java Reflection Beispielanalyse#🎜🎜##🎜🎜#Um es einfach auszudrücken, das ist es#🎜🎜#
      #🎜🎜#method.invoke(class or class object)#🎜 🎜#
      #🎜🎜# Zuerst ruft forName die Klasse ab, dann ruft newInstance das Klassenobjekt ab, dann ruft getMethod die Methode ab und ruft dann auf #🎜🎜##🎜🎜#Rce-Beispiel für Runtime (Durchbruch bei der Zugriffsbeschränkung) # 🎜🎜##🎜🎜#Es gibt eine exec in der Runtime-Klassenmethode. Sie können den Befehl #🎜🎜#rrreee#🎜🎜# ausführen, aber einen Fehler finden #🎜🎜##🎜🎜#Analyse von Beispielen für Anwendungsmethoden der Java-Reflexion#🎜🎜##🎜🎜#Der Grund für dieses Problem : #🎜🎜#
      • #🎜🎜#Die verwendete Klasse hat keinen parameterlosen Konstruktor#🎜🎜#
      • #🎜🎜#Der verwendete Klassenkonstruktor ist privat#🎜🎜#
      • #🎜🎜##🎜 🎜#Dann ist die Lösung setAccessible(true);, verwenden Sie dies, um Zugriffsbeschränkungen zu durchbrechen#🎜🎜#

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

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

        Verwendung von Java-Reflexion und Analyse von Beispielen

        那么这里我们就可以这么去突破限制 先获取构造方法,然后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");
            }
        }

        Verwendung von Java-Reflexion und Analyse von Beispielen

        这里有一个疑问,如果把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

    Das obige ist der detaillierte Inhalt vonVerwendung von Java-Reflexion und Analyse von Beispielen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

    Stellungnahme:
    Dieser Artikel ist reproduziert unter:yisu.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen