オブジェクトはリフレクションを通じてクラスを取得でき、クラスはすべてのメソッド (Private を含む) を取得できます。 Java 言語のリフレクション機構を通じて、バイトコード ファイルを操作したり、バイトコード ファイルを読み取ったり変更したりすることができます。 #a. forName() メソッド
public class test1 { public static void main(String[] args) throws ClassNotFoundException { Class name = Class.forName("java.lang.Runtime"); System.out.println(name); } }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); } }
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); } }
特定のメソッドを取得します。最初のパラメータはメソッド名です。2 番目のパラメータは、メソッドのパラメータに対応するクラス オブジェクトです。たとえば、ここでの Runtime の exec メソッド パラメータは文字列なので、2 番目のパラメータは文字列です。ここのパラメータは 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
継承されたクラスのパブリック メソッドを含む、クラスのすべてのパブリック メソッドを返しますd.getMethodパラメータは getDeclaredMethod3 と同じです。メンバー変数の取得Methoda のメソッドと同様です。getDeclaredFieldsすべての変数配列を取得しますgetDeclaredField(String name)Get specific、パラメータは目的のメソッドの名前ですc. getFields()同様に、public のみを取得できますが、親クラスが含まれますd. getField(String name)同様に、パラメータは、目的のメソッドの名前です。4. コンストラクターを取得します ConstructorConstructor>[] getConstructors(): パブリック コンストラクターのみを返します
Constructor getConstructor(class>...parameterTypes): パラメーターの型と一致するパブリック コンストラクターと一致します
を生成できます。リフレクションを通じてオブジェクトをインスタンス化します。一般に、Class オブジェクトの#後の 2 つのメソッドのパラメーターは、次の 2 つのメソッドの型のクラス オブジェクトです。 Method のパラメーターに似たメソッド パラメーター (例:
String.class5)。リフレクションによってクラス オブジェクトを作成します
newInstance
newInstance()# を使用します。 ##クラス オブジェクトを作成するメソッド作成方法は次のとおりです: newInstance メソッドを作成するだけです。 forname メソッドを通じて取得されたクラス オブジェクト
Class c = Class.forName("com.reflect.MethodTest"); // 创建Class对象 Object m1 = c.newInstance(); // 创建类对象
使用法: <pre class="brush:java;">public Object invoke(Object obj, Object... args)</pre>
最初のパラメータはクラスのインスタンス、2 番目のパラメータは対応する関数のパラメータです
obj: 基礎となるメソッドの元となるオブジェクトが呼び出されます。インスタンス化されたオブジェクトである必要があります。
である可能性がありますが、最初のパラメータはメソッドを呼び出すことはできません。修正されていません:
このメソッドの呼び出しが通常のメソッドの場合、最初のパラメータはクラス オブジェクトです。
このメソッドの呼び出しが静的メソッドである場合、最初のパラメータはクラスです。
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("测试成功"); } }
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"); } }
しかし、次のことが判明しました。エラーが報告されましたこの問題の理由:
##使用されたクラスにはパラメータのないコンストラクターがありません
使用されるクラス コンストラクターは private
その場合、解決策はJava.lang.reflect.AccessibleObject类是Field,Method和Constructor类对象的基类,可以提供将反射对象标记为使用它抑制摸人Java访问控制检查的功能,同时上述的反射类中的Field,Method和Constructor继承自AccessibleObject。所以我们在这些类方法基础上调用setAccessible()方法,既可对这些私有字段进行操作
简单来说,私有的属性、方法、构造方法,可以通过这个去突破限制,xxx.setAccessible(true)
可以看到Runtime的构造方法是private的
那么这里我们就可以这么去突破限制 先获取构造方法,然后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"); } }
这里有一个疑问,如果把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 中国語 Web サイトの他の関連記事を参照してください。