ホームページ Java &#&チュートリアル Java リフレクション メカニズムの詳細な説明

Java リフレクション メカニズムの詳細な説明

Jun 23, 2017 pm 04:38 PM
java 反射 機構 深く行く 詳しい説明

1. 概念

リフレクションとは、Java のさまざまなコンポーネントを対応する Java クラスにマッピングすることです。

Classクラスの構築メソッドはプライベートであり、JVMによって作成されます。

リフレクションはJava言語の機能で、プログラムが実行時に自己チェックを実行し、内部メンバーを操作できるようにします(コンパイルされないことに注意してください)。たとえば、Java クラスがすべてのメンバー変数とメソッドを取得して表示できるようになります。 Java のこの機能は実際のアプリケーションではあまり使用されないかもしれませんが、この機能は他のプログラミング言語にはまったく存在しません。たとえば、Pascal、C、または C++ では、プログラム内の関数定義に関する情報を取得する方法がありません。 (Sun より)

JavaBean はリフレクションの実用的なアプリケーションの 1 つで、これにより一部のツールがソフトウェア コンポーネントを視覚的に操作できるようになります。これらのツールは、リフレクションを通じて Java コンポーネント (クラス) のプロパティを動的にロードして取得します。

リフレクションは 1.2 から存在します。クラス "Class" に関しては、そのオブジェクトがメモリ内のバイトコードであるため、すべてリフレクション メカニズムが使用されます。

クラス クラスのインスタンスは、実行中の Java アプリケーション内のクラスとインターフェイスを表します。列挙はクラスであり、アノテーションはインターフェイスです。各配列は、Class オブジェクトにマップされるクラスに属し、同じ要素の型と次元を持つすべての配列で共有されます。基本的な Java 型 (boolean、byte、char、short、int、long、float、double) とキーワード void も Class オブジェクトとして表されます。クラスにはパブリック コンストラクターがありません。クラスオブジェクトは、クラスがロードされるとき、およびクラスローダーでdefineClassメソッドを呼び出すことによって、Java仮想マシンによって自動的に構築されます。

1 Person p1 = new Person();
2 //下面的这三种方式都可以得到字节码
3 CLass c1 = Date.class();
4 p1.getClass(); 
5 //若存在则加载,否则新建,往往使用第三种,类的名字在写源程序时不需要知道,到运行时再传递过来
6 Class.forName("java.lang.String");
ログイン後にコピー
CLass.forName() バイトコードは、バイトコードを取得するために Java 仮想マシンにロードされています。バイトコードは Java 仮想マシンでまだ生成されておらず、ロードされたバイトコードはクラスローダーにバッファリングされます。仮想マシン。

以下の簡単な例を考慮して、リフレクションがどのように機能するかを見てみましょう。

import java.lang.reflect.*;  

public class DumpMethods {  
   public static void main(String args[]) {  
      try {  
           Class c = Class.forName("java.util.Stack");  

           Method m[] = c.getDeclaredMethods();  
             
           for (int i = 0; i < m.length; i++)  
               System.out.println(m[i].toString());  
      }  
      catch (Throwable e){  
            System.err.println(e);  
      }  
   }  
}
ログイン後にコピー

1 public synchronized java.lang.Object java.util.Stack.pop() 
2 public java.lang.Object java.util.Stack.push(java.lang.Object) 
3 public boolean java.util.Stack.empty() 
4 public synchronized java.lang.Object java.util.Stack.peek() 
5 public synchronized int java.util.Stack.search(java.lang.Object)
ログイン後にコピー

これには、java.util.Stack クラスのメソッド名とその修飾子および戻り値の型がリストされます。このプログラムは、Class.forName を使用して指定されたクラスをロードし、次に getDeclaredMethods を呼び出してクラスで定義されているメソッドのリストを取得します。 java.lang.reflect.Methods は、クラス内の単一のメソッドを記述するために使用されるクラスです。

次の例では、Class オブジェクトを使用して、オブジェクトのクラス名を表示します:

1 void printClassName(Object obj) {
2          System.out.println("The class of " + obj +
3                             " is " + obj.getClass().getName());
4      }
ログイン後にコピー
クラス リテラル (JLS セクション 15.8.2) を使用して、指定された型 (または void) の Class オブジェクトを取得することもできます。 。例:

1 System.out.println("The name of class Foo is: "+Foo.class.getName());
ログイン後にコピー
オブジェクトインスタンスがない場合、主に 2 つのメソッドがあります。

//获得类类型的两种方式        
Class cls1 = Role.class;        
Class cls2 = Class.forName("yui.Role");
ログイン後にコピー
2 番目のメソッドでは、forName のパラメータは完全なクラス名 (パッケージ名 + クラス名) である必要があり、このメソッドは例外をキャッチする必要があることに注意してください。 cls1 を用意したので、Class の newInstance メソッドを使用して、クラスのデフォルトのコンストラクターを呼び出すことと同じように、Role クラスのインスタンスを作成できます。

1 Object o = cls1.newInstance(); 
2 //创建一个实例        
3 //Object o1 = new Role();   //与上面的方法等价
ログイン後にコピー

2. よく使用されるメソッド

1. isPrimitive (バイトコードの基本タイプであるかどうかを判断します)

public class TestReflect {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String str = "abc";
        Class cls1 = str.getClass();
        Class cls2 = String.class;
        Class cls3 = null;//必须要加上null
        try {
            cls3 = Class.forName("java.lang.String");
        } catch (ClassNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        System.out.println(cls1==cls2);
        System.out.println(cls1==cls3);
        
        System.out.println(cls1.isPrimitive());
        System.out.println(int.class.isPrimitive());//判定指定的 Class 对象是否表示一个基本类型。
        System.out.println(int.class == Integer.class);
        System.out.println(int.class == Integer.TYPE);
        System.out.println(int[].class.isPrimitive());
        System.out.println(int[].class.isArray());
    }
}
/*
 * true
true
false
true
false
true
false
true

 */
*/
ログイン後にコピー
2. getConstructor および getConstructors()

構築メソッドの順序はありませんjava、スルー パラメータのタイプと数によって区別されます。

1 public class TestReflect {
2     public static void main(String[] args) throws SecurityException, NoSuchMethodException {
3         // TODO Auto-generated method stub
4         String str = "abc";
5         
6         System.out.println(String.class.getConstructor(StringBuffer.class));
7     }
8 }
ログイン後にコピー
3. Filedクラスは、あるクラスのメンバ変数を表します。

 1 import java.lang.reflect.Field;
 2 public class TestReflect {
 3     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 4         ReflectPointer rp1 = new ReflectPointer(3,4);
 5         Field fieldx = rp1.getClass().getField("x");//必须是x或者y
 6         System.out.println(fieldx.get(rp1));
 7         
 8         /*
 9          * private的成员变量必须使用getDeclaredField,并setAccessible(true),否则看得到拿不到
10          */
11         Field fieldy = rp1.getClass().getDeclaredField("y");
12         fieldy.setAccessible(true);//暴力反射
13         System.out.println(fieldy.get(rp1));
14         
15     }
16 }
17 
18 class ReflectPointer {
19     
20     public int x = 0;
21     private int y = 0;
22     
23     public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
24         super();
25         // TODO Auto-generated constructor stub
26         this.x = x;
27         this.y = y;
28     }
29 }
ログイン後にコピー
4.

3. 代表的な例

1. すべてのString型メンバ変数のbをaに変更します。

 1 import java.lang.reflect.Field;
 2 public class TestReflect {
 3     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 4         ReflectPointer rp1 = new ReflectPointer(3,4);
 5         changeBtoA(rp1);
 6         System.out.println(rp1);
 7         
 8     }
 9     
10     private static void changeBtoA(Object obj) throws RuntimeException, Exception {
11         Field[] fields = obj.getClass().getFields();
12         
13         for(Field field : fields) {
14             //if(field.getType().equals(String.class))
15             //由于字节码只有一份,用equals语义不准确
16             if(field.getType()==String.class) {
17                 String oldValue = (String)field.get(obj);
18                 String newValue = oldValue.replace(&#39;b&#39;, &#39;a&#39;);
19                 field.set(obj,newValue);
20             }
21         }
22     }
23 }
24 
25 class ReflectPointer {
26     
27     private int x = 0;
28     public int y = 0;
29     public String str1 = "ball";
30     public String str2 = "basketball";
31     public String str3 = "itcat";
32     
33     public ReflectPointer(int x,int y) {//alt + shift +s相当于右键source
34         super();
35         // TODO Auto-generated constructor stub
36         this.x = x;
37         this.y = y;
38     }
39 
40     @Override
41     public String toString() {
42         return "ReflectPointer [str1=" + str1 + ", str2=" + str2 + ", str3="
43                 + str3 + "]";
44     }
45 }
ログイン後にコピー
2. ユーザーが指定したクラス名に基づいて、クラス内の main メソッドを呼び出すプログラムを作成します。

なぜリフレクションを使うのでしょうか?

 1 import java.lang.reflect.Field;
 2 import java.lang.reflect.Method;
 3 
 4 public class TestReflect {
 5     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 6         String str = args[0];
 7         /*
 8          * 这样会数组角标越界,因为压根没有这个字符数组
 9          * 需要右键在run as-configurations-arguments里输入b.Inter(完整类名)
10          * 
11          */
12         Method m = Class.forName(str).getMethod("main",String[].class);
13         //下面这两种方式都可以,main方法需要一个参数
14         
15         m.invoke(null, new Object[]{new String[]{"111","222","333"}});
16         m.invoke(null, (Object)new String[]{"111","222","333"});//这个可以说明,数组也是Object
17         /*
18          * m.invoke(null, new String[]{"111","222","333"})
19          * 上面的不可以,因为java会自动拆包
20          */
21     }
22 }
23 
24 class Inter {
25     public static void main(String[] args) {
26         for(Object obj : args) {
27             System.out.println(obj);
28         }
29     }
30 }
ログイン後にコピー
3.instanceofoperatorをシミュレートします

class S {  
}   

public class IsInstance {  
   public static void main(String args[]) {  
      try {  
           Class cls = Class.forName("S");  
           boolean b1 = cls.isInstance(new Integer(37));  
           System.out.println(b1);  
           boolean b2 = cls.isInstance(new S());  
           System.out.println(b2);  
      }  
      catch (Throwable e) {  
           System.err.println(e);  
      }  
   }  
}
ログイン後にコピー

この例では、クラス S の Class オブジェクトが作成され、いくつかのオブジェクトが S のインスタンスであるかどうかを確認します。 Integer(37) はそうではありませんが、new S() はそうです。

4.メソッドクラス

(オブジェクトではなく)クラス内のメソッドを表します。

 1 import java.lang.reflect.Field;
 2 import java.lang.reflect.Method;
 3 /*
 4  * 人在黑板上画圆,涉及三个对象,画圆需要圆心和半径,但是是私有的,画圆的方法
 5  * 分配给人不合适。
 6  * 
 7  * 司机踩刹车,司机只是给列车发出指令,刹车的动作还需要列车去完成。
 8  * 
 9  * 面试经常考面向对象的设计,比如人关门,人只是去推门。
10  * 
11  * 这就是专家模式:谁拥有数据,谁就是专家,方法就分配给谁
12  */
13 public class TestReflect {
14     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
15         String str = "shfsfs";
16         //包开头是com表示是sun内部用的,java打头的才是用户的
17         Method mtCharAt = String.class.getMethod("charAt", int.class);
18         Object ch = mtCharAt.invoke(str,1);//若第一个参数是null,则肯定是静态方法
19         System.out.println(ch);
20         
21         System.out.println(mtCharAt.invoke(str, new Object[]{2}));//1.4语法
22         
23     }
24     
25 }
ログイン後にコピー

5. 配列リフレクション

配列ツールクラスは、配列のリフレクション操作を完了するために使用されます。

同じ型、同じ緯度のバイトコードは同じです。

int.classとInteger.classは同じバイトコードではなく、Integer.TYPE、TYPEはパッケージングクラスに対応する基本クラスのバイトコードを表す int.class==Integer.TYPE

 1 import java.util.Arrays;
 2 
 3 /*
 4  * 从这个例子看出即便字节码相同但是对象也不一定相同,根本不是一回事
 5  * 
 6  */
 7 public class TestReflect {
 8     public static void main(String[] args) throws SecurityException, NoSuchMethodException, NoSuchFieldException, IllegalArgumentException, Exception {
 9         int[] a = new int[3];
10         int[] b = new int[]{4,5,5};//直接赋值后不可以指定长度,否则CE
11         int[][] c = new int[3][2];
12         String[] d = new String[]{"jjj","kkkk"};
13         System.out.println(a==b);//false
14         System.out.println(a.getClass()==b.getClass());//true
15         //System.out.println(a.getClass()==d.getClass());    //比较字节码a和cd也没法比
16         System.out.println(a.getClass());//输出class [I
17         System.out.println(a.getClass().getName());//输出[I,中括号表示数组,I表示整数
18         
19         System.out.println(a.getClass().getSuperclass());//输出class java.lang.Object
20         System.out.println(d.getClass().getSuperclass());//输出class java.lang.Object
21         
22         //由于父类都是Object,下面都是可以的
23         Object obj1 = a;//不可是Object[]
24         Object obj2 = b;
25         Object[] obj3 = c;//基本类型的一位数组只可以当做Object,非得还可以当做Object[]
26         Object obj4 = d;
27         
28         //注意asList处理int[]和String[]的区别
29         System.out.println(Arrays.asList(b));//1.4没有可变参数,使用的是数组,[[I@1bc4459]
30         System.out.println(Arrays.asList(d));//[jjj, kkkk]
31         
32     }
33 }
ログイン後にコピー

6. 結論
上記はリフレクション メカニズムの単純な使用法です。Spring を学習したことがある方は、オブジェクトを作成するときに、文字列の実装を渡す理由を理解しているはずです。必要なものをそのまま作成し、Object を使用しています。これは、Java 言語の動的な特性と依存性が大幅に軽減されていることを示しています。

Javaを学習している学生の皆さん、注意してください! ! !
学習プロセス中に問題が発生した場合、または学習リソースを入手したい場合は、Java 学習交換グループ (159610322) に参加してください。一緒に Java を学びましょう!

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

このウェブサイトの声明
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。

ホットAIツール

Undresser.AI Undress

Undresser.AI Undress

リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover

AI Clothes Remover

写真から衣服を削除するオンライン AI ツール。

Undress AI Tool

Undress AI Tool

脱衣画像を無料で

Clothoff.io

Clothoff.io

AI衣類リムーバー

AI Hentai Generator

AI Hentai Generator

AIヘンタイを無料で生成します。

ホットツール

メモ帳++7.3.1

メモ帳++7.3.1

使いやすく無料のコードエディター

SublimeText3 中国語版

SublimeText3 中国語版

中国語版、とても使いやすい

ゼンドスタジオ 13.0.1

ゼンドスタジオ 13.0.1

強力な PHP 統合開発環境

ドリームウィーバー CS6

ドリームウィーバー CS6

ビジュアル Web 開発ツール

SublimeText3 Mac版

SublimeText3 Mac版

神レベルのコード編集ソフト(SublimeText3)

Javaの完全数 Javaの完全数 Aug 30, 2024 pm 04:28 PM

Java における完全数のガイド。ここでは、定義、Java で完全数を確認する方法、コード実装の例について説明します。

ジャワのウェカ ジャワのウェカ Aug 30, 2024 pm 04:28 PM

Java の Weka へのガイド。ここでは、weka java の概要、使い方、プラットフォームの種類、利点について例を交えて説明します。

Javaのスミス番号 Javaのスミス番号 Aug 30, 2024 pm 04:28 PM

Java のスミス番号のガイド。ここでは定義、Java でスミス番号を確認する方法について説明します。コード実装の例。

Java Springのインタビューの質問 Java Springのインタビューの質問 Aug 30, 2024 pm 04:29 PM

この記事では、Java Spring の面接で最もよく聞かれる質問とその詳細な回答をまとめました。面接を突破できるように。

Java 8 Stream Foreachから休憩または戻ってきますか? Java 8 Stream Foreachから休憩または戻ってきますか? Feb 07, 2025 pm 12:09 PM

Java 8は、Stream APIを導入し、データ収集を処理する強力で表現力のある方法を提供します。ただし、ストリームを使用する際の一般的な質問は次のとおりです。 従来のループにより、早期の中断やリターンが可能になりますが、StreamのForeachメソッドはこの方法を直接サポートしていません。この記事では、理由を説明し、ストリーム処理システムに早期終了を実装するための代替方法を調査します。 さらに読み取り:JavaストリームAPIの改善 ストリームを理解してください Foreachメソッドは、ストリーム内の各要素で1つの操作を実行する端末操作です。その設計意図はです

Java での日付までのタイムスタンプ Java での日付までのタイムスタンプ Aug 30, 2024 pm 04:28 PM

Java での日付までのタイムスタンプに関するガイド。ここでは、Java でタイムスタンプを日付に変換する方法とその概要について、例とともに説明します。

カプセルの量を見つけるためのJavaプログラム カプセルの量を見つけるためのJavaプログラム Feb 07, 2025 am 11:37 AM

カプセルは3次元の幾何学的図形で、両端にシリンダーと半球で構成されています。カプセルの体積は、シリンダーの体積と両端に半球の体積を追加することで計算できます。このチュートリアルでは、さまざまな方法を使用して、Javaの特定のカプセルの体積を計算する方法について説明します。 カプセルボリュームフォーミュラ カプセルボリュームの式は次のとおりです。 カプセル体積=円筒形の体積2つの半球体積 で、 R:半球の半径。 H:シリンダーの高さ(半球を除く)。 例1 入力 RADIUS = 5ユニット 高さ= 10単位 出力 ボリューム= 1570.8立方ユニット 説明する 式を使用してボリュームを計算します。 ボリューム=π×R2×H(4

Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Spring Tool Suiteで最初のSpring Bootアプリケーションを実行するにはどうすればよいですか? Feb 07, 2025 pm 12:11 PM

Spring Bootは、Java開発に革命をもたらす堅牢でスケーラブルな、生産対応のJavaアプリケーションの作成を簡素化します。 スプリングエコシステムに固有の「構成に関する慣習」アプローチは、手動のセットアップを最小化します。

See all articles