Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します

WBOY
リリース: 2022-03-03 17:45:15
転載
1844 人が閲覧しました

この記事では、java のリフレクション機構に関する問題を中心に、Java に関する知識をお届けします Java 言語のプログラム情報を動的に取得したり、オブジェクトを動的に呼び出す機能をリフレクションといいます。 , 皆様のお役に立てれば幸いです。

Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します

推奨される学習: 「java チュートリアル

偉い人の話を聞いたり、フォーラムやその他の学習方法を見るたびにjavaの脆弱性を逆シリアル化する際に、リフレクションメカニズムという言葉があります。上司はこの言葉を使ってペイロードを作成します。Javaの逆シリアル化を学んだばかりの人にとっては、少し混乱するかもしれません。とにかく、私は混乱しています。それで私はすぐに教訓を学びました。そうしないと、私と偉い人たちとの差はますます広がってしまいます。したがって、この記事では主に Java リフレクション メカニズムについて説明します

Java リフレクション メカニズム

Java のリフレクション (リフレクション) メカニズムとは、プログラムの実行状態で、任意のクラスのオブジェクトを構築できることを意味します。理解できる 任意のオブジェクトが属するクラスは、任意のクラスのメンバー変数とメソッドを理解でき、任意のオブジェクトのプロパティとメソッドを呼び出すことができます。この動的にプログラム情報を取得し、動的にオブジェクトを呼び出す機能をJava言語のリフレクション機構と呼びます。リフレクションは動的言語の鍵とみなされます。

私は言葉で表現するのがあまり得意ではないので、上の写真を例にしてみましょう

反射機構なし

//定义一个animals接口interface animals {
    public abstract void print();}//定义类来实现animals接口的抽象方法class Dog implements animals {
    public void print() {
        System.out.println("Dog");
    }}class Cat implements animals {
    public void print() {
        System.out.println("Cat");
    }}// 构造一个zoo类// 之后如果我们在添加其他的实例的时候只需要修改zoo类class zoo {

    public static animals getInstance(String animalsName) {
        animals a = null;
        if ("Dog".equals(animalsName)) {
            a = new Dog();
        }
        if ("Cat".equals(animalsName)) {
            a = new Cat();
        }
        return a;
    }}public class reflection {
    public static void main(String[] args) {
        //借助zoo类寻找对应的类来实现接口
        animals a=zoo.getInstance("Cat");
        if(a!=null)
            a.print();
    }}
ログイン後にコピー

この時点で動物を追加するには、 just

  • クラスを追加
  • zooを変更
  • #main関数のanimalクラスを変更
  • ##上記をリフレクション機構に変更
//定义一个animals接口interface animals {
    public abstract void print();}//定义类来实现animals接口的抽象方法class Dog implements animals {
    public void print() {
        System.out.println("Dog");
    }}class Cat implements animals {
    public void print() {
        System.out.println("Cat");
    }}// 构造一个zoo类// 之后如果我们在添加其他的实例的时候只需要修改zoo类class zoo {

    public static animals getInstance(String className) {
        animals a = null;
        try {
            //借助Class.forName寻找类名,并用newInstance实例化类似于new
            a = (animals) Class.forName(className).newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return a;
    }}public class reflection {
    public static void main(String[] args) {
        //借助zoo类寻找对应的类来实现接口(classname为当前包名加类名)
        animals a = zoo.getInstance("com.cc1.Dog");
        if (a != null)
            a.print();
    }}
ログイン後にコピー

この時点で動物を追加する必要があるのは、

クラスを追加する
  • メイン関数の動物クラスを変更する
  • ステップが節約され、受信クラス名は制御可能で、存在しているように見えます。 クラスは調整できます。

#リフレクション メカニズムのメソッド

#私たちが最もよく使用するものは、おそらく

## です。 #forName (クラスの呼び出し)

    getMethod (以下のクラスメソッドの呼び出し)
  • invoke (実行)
  • newInstance (インスタンス化されたオブジェクト)
Class.forName(className).getMethod(methodName).invoke(Class.forName(className).newInstance());
ログイン後にコピー
  • 以下では、リフレクション メカニズムを使用して、コンピューター (calc) またはメモ帳 (notepad) をポップアップ表示します
  • コンピューターにはたくさんのポップアップがあるため、今回はメモ帳だけを再生します。ポップアップできるのは素晴らしいことです

    Runtime.getRuntime().exec("notepad");
    ログイン後にコピー

    getRuntime 関数を見てみましょう

    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    この関数がランタイムのための方法であることを学びましたオブジェクトを取得するためのクラスです 個人的には毎回呼び出すのが面倒に感じます オブジェクト作成のために一度呼び出さないように関数にカプセル化しています
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    クラスの取得方法object

    Class.forName (クラス名を取得)

      zoo.class (ロード済みのクラス)
    • obj .class (インスタンス)

    • Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します#クラスの初期化

    Zoo クラスを変更し、初期ブロック、静的初期ブロック、コンストラクターを追加します

    class zoo {
        //初始块
        {
            System.out.println("1  " + this.getClass());
        }
    
        //静态初始块
        static {
            System.out.println("2  " + zoo.class);
        }
    
        public zoo() {
            System.out.println("3  " + this.getClass());
        }
    
        public static animals getInstance(String className) {
            animals a = null;
            try {
                //借助Class.forName寻找类名,并用newInstance实例化类似于new
                a = (animals) Class.forName(className).newInstance();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return a;
        }}
    ログイン後にコピー

    クラス初期化実行シーケンス

    : 静的初期ブロック

    クラスインスタンス化実行シーケンス
    : 静的初期ブロック→初期ブロック→コンストラクターJava デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    このことから、クラスの初期化とクラスのインスタンス化は異なることがわかります
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    次に、zoo1 クラスを追加して、zoo クラスを継承します

    class zoo1 extends zoo{
        //初始块
        {
            System.out.println("11  " + this.getClass());
        }
    
        //静态初始块
        static {
            System.out.println("12  " + zoo.class);
        }
    
        public zoo1() {
            System.out.println("13  " + this.getClass());
        }}
    ログイン後にコピー

    サブクラスの初期化シーケンス

    : 親クラスの静的初期化ブロック - > サブクラスの静的初期化ブロック

    #サブクラスのインスタンス化シーケンス
    : 親クラスの静的初期化ブロック - > サブクラスの静的初期化ブロック - >親クラスの初期化ブロック - > 親クラスのコンストラクター - > サブクラスの初期化ブロック - > サブクラスのコンストラクターJava デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    # #上記のことから、Class.forName が使用され、クラスが静的初期化ブロックは制御可能であり、任意のコードを実行できます。
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します#内部クラスの呼び出し
    #Class.forName("java.lang.Runtime" ) クラスを取得します (java.lang.Runtime は Runtime クラスのフルパスです)

    getMethod

    getMethod の関数は次のとおりです。リフレクションを通じてクラスの特定のパブリック メソッドを取得します。
    Java はクラスのオーバーロードをサポートしていますが、関数は関数名だけでは決定できないため、getMethod を呼び出すときは、パラメーターの型のリストをそのメソッドに渡す必要があります。

    Class.forName("java.lang.Runtime ") .getMethod(“exec”, String.class)

    invoke


    静态和动态方法的区别
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します

    invoke方法在getMethod类下,作用时传递参数,执行方法
    public Object invoke(Object obj, Object… args)
    第一个参数是getMethod获取的方法的类对象(如果方法是静态方法则传类)
    获取exec函数的类对象
    Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”))
    由于getRuntime是静态方法,所以传类
    invoke(Class.forName(“java.lang.Runtime”).getMethod(“getRuntime”).invoke(Class.forName(“java.lang.Runtime”)),“calc.exe”)

    最后我们合并一下

    Class.forName("java.lang.Runtime").
                    getMethod("exec", String.class).
                    invoke(Class.forName("java.lang.Runtime").getMethod("getRuntime").invoke(Class.forName("java.lang.Runtime")), "notepad");
    ログイン後にコピー

    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します

    指定构造方法生成实例

    String str="notepad";ProcessBuilder pb = new ProcessBuilder(str);pb.start();
    ログイン後にコピー

    getConsturctor(函数可以选定指定接口格式的构造函数(由于构造函数也可以根据参数来进行重载)
    选定后我们可以通过newInstance(),并传入构造函数的参数执行构造函数

    ProcessBuilder类有两个构造函数

    • public ProcessBuilder(String… command)(String…变长的字符串数组String[].class)
    • public ProcessBuilder(List command)

    分别使用构造方法

    • Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[][]{{“notepad”}})
    • Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))

    执行完构造方法实例后,在进行强制转化使用start函数即可

    ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

    实际中,肯定用不了,哪有这么好的事,还是接着反射把

    Class.forName(“java.lang.ProcessBuilder”).getMethod(“start”).invoke(clazz.getConstructor(List.class).newInstance(Arrays.asList(“notepad”)));
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    这里可能有人会好奇我写的里那的另一个构造函数,String…command这个传参为什么用new String[][]{{“notepad”}},不应该是new String[]{“notepad”},现在用应该的

    ((ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(String[].class).newInstance(new String[]{“notepad”})).start();

    在这行打断点调试
    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    我们传的是一个字符串数组到了实例化的时候变成了一个字符串,再看看另一个构造函数(List)

    ( (ProcessBuilder) Class.forName(“java.lang.ProcessBuilder”).getConstructor(List.class).newInstance(Arrays.asList(“notepad”))).start();

    依旧还是这行打断点

    Java デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明します
    由此可知,List传入时会被当作Object的第一项,而String[]会被当做Object,所以多加一层[]{}

    执行私有方法

    通过函数getDeclaredConstructor获取私有方法,再利用setAccessible(true)打破私有方法限制

    Class cls = Class.forName("java.lang.Runtime"); 
    Constructor m = cls.getDeclaredConstructor();
     m.setAccessible(true); 
     cls.getMethod("exec", String.class).invoke(m.newInstance(), "notepad");
    ログイン後にコピー

     推荐学习:《java视频教程

    以上がJava デシリアライゼーションのリフレクション メカニズムを例とともに詳しく説明しますの詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

    関連ラベル:
    ソース:csdn.net
    このウェブサイトの声明
    この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。
    人気のチュートリアル
    詳細>
    最新のダウンロード
    詳細>
    ウェブエフェクト
    公式サイト
    サイト素材
    フロントエンドテンプレート
    私たちについて 免責事項 Sitemap
    PHP中国語ウェブサイト:福祉オンライン PHP トレーニング,PHP 学習者の迅速な成長を支援します!