1.反射の定義
リフレクションの定義: Java のリフレクション メカニズムは、実行状態では、任意のクラスについて、このクラスのすべてのプロパティとメソッドを知ることができ、任意のオブジェクトについて、そのメソッドとプロパティを呼び出すことができるというものです。 、次に、型情報の一部を変更できます。このように情報を動的に取得し、オブジェクトメソッドを動的に呼び出す機能をリフレクション機構と呼びます。
リフレクション メカニズムとは、クラスまたはオブジェクト (パブリックまたはプリベットの変更に関係なく) の任意のメソッドとプロパティを実行状態で取得できることを意味します。
例:大学が開校した場合、大学生は開校期間中、様々な交通機関を利用して通学しなければならず、飛行機、電車、バスで通学する学生もいます。ツールは、該当する交通機関に乗る前に、該当する駅でセキュリティ チェックを通過する必要があり、セキュリティ チェックを通過すると、スーツケースと持ち物をセキュリティ チェック機に入れ、スキャンする必要があります。 、彼らは対応する通過することができます デバイスは、スーツケースと機内持ち込み禁止のアイテムに禁止されているアイテムがあるかどうかを確認します
2. 振り返りの目的
クラス内の一部のプロパティとメソッドがプライベートであるか、システム アプリケーションに対してのみ開かれている場合、リフレクションを使用して、必要なプライベート プロパティとメソッドを取得できます。
リフレクションの最も重要な用途は、さまざまな一般的なフレームワークを開発することです
3. リフレクションに関連する重要なクラス
クラス名 |
使用 |
クラスクラス |
実行中の Java アプリケーションのクラスとインターフェイスを表す、クラスを表すエンティティ |
フィールドクラス |
クラスのメンバー変数/クラスの属性を表します |
メソッドクラス |
デリゲート クラスのメソッド |
コンストラクター クラス |
デリゲート クラス コンストラクター |
4. リフレクション メカニズムの起源: Class クラス
クラスはクラスのエンティティを表し、実行中の Java アプリケーションのクラスとインターフェースを表します
Java ファイルがコンパイルされると、.class ファイルが生成され、JVM はこの時点で .class ファイルを解釈します. コンパイルされた Java ファイル .class も JVM によってオブジェクトに解析され、このオブジェクトは Java. lang.class. プログラムの実行中、各 Java ファイルは最終的に Class クラス オブジェクトのインスタンスになります。Java のリフレクション メカニズムを介してこのインスタンスに適用し、このクラスの属性とアクションを取得または追加および変更して、このクラスを動的クラスにすることができます。
5. Class クラスの関連メソッド
クラスを取得するためによく使用されるメソッド
方法 |
用途 |
getClassLoader() |
获得类的加载器 |
getDeclareClasses() |
返回一个数组,数组中包含该类中所有类和接口类的对象(包括私有的) |
forName(String classNme) |
根据类名返回类的对象 |
newInstance() |
创建类的实例 |
getName() |
获得类的完整路径名字 |
常用获得类中属性相关的方法(以下方法返回值为Field)
方法 |
用途 |
getField(String name) |
获得某个公有的属性对象 |
getFields() |
获得所有公有的属性对象 |
getDeclaredField(String name) |
获得某个属性对象 |
getDeclaredFields() |
获得所有属性对象 |
获得类中注解相关的方法
方法 |
用途 |
getAnnotation(Class annotationClass) |
返回该类中与参数类型匹配的公有注解对象 |
getAnnotations() |
返回该类所有的公有注解对象 |
getDeclaredAnnotation(Class annotationClass) |
返回该类中与参数类型匹配的所有注解对象 |
getDeclaredAnnotations() |
返回该类所有的注解对象 |
获得类中方法相关的方法 (以下方法返回值为Method 相关)
方法 |
用途 |
getMethod(String name,Class...<?> parameterTypes) |
获得该类某个公有方法 |
getMethod() |
获得该类所有公有的方法 |
getDeclaredMethod(String name,Class...<?> parameterTypes) |
获得该类某个方法 |
getDeclaredMethod() |
获得该类所有方法 |
获得类中构造器相关的方法(以下方法返回值为Constructor相关)
方法 |
用途 |
getConstructor(Class...<?> parameterTypes ) |
获得该类中与参数类型匹配的公有构造方法 |
getConstructors() |
获得该类的所有公有构造方法 |
getDeclaredConstructor(Class...<?> parameterTypes) |
获得该类中与参数类型匹配的构造方法 |
getDeclaredConstructors() |
获得该类所有构造方法 |
6、 获得 Class 对象
我们想要进行反射,首先得拿到需要反射类的Class对象,通过 Class 对象的核心方法,来进行反射。
获得Class对象分别有三种方法:
使用类对象的 getClass() 方法
使用 .class 方法,仅时候在编译前就已经明确要操作的Class
使用Class.forName("类得全路径名"),这个forName是Class这个类的静态方法,这个获取Class对象的前提条件就是知道类的全路径名
示例:
public class Student {
private String name = "张三";//私有属性
public int age = 18;//公共属性
//不带参数的构造方法
public Student(){
System.out.println("Student()");
}
//带参数的私有构造方法
private Student(String name,int age) {
this.name = name;
this.age = age;
System.out.println("Student(String,name)");
}
//私有方法
private void eat(){
System.out.println("i am eat");
}
//公共方法
public void sleep(){
System.out.println("i am sleep");
}
//带有参数的私有方法
private void function(String str) {
System.out.println(str);
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
现在我们就通过获取 Class 对象的三种方法,分别来获取上述的 Student 类的 Class 对象
使用类对象的 getClass() 方法获取:
public static void main(String[] args) {
Student student = new Student();
Class<?> s1 = student.getClass();
}
使用 .class 方法获取:
直接通过 类名.class 的方式获得到的Class对象的方法最为安全可靠,程序性能也会更高,直接通过 类型.class 的方式获得到,也就说明任何一个类都有一个隐含的静态成员变量class
public static void main(String[] args) {
Class<?> s2 = Student.class;
}
使用Class.forName("类得全路径名") 方法获取:
通过 Class 对象的 forName() 静态方法来获取,可能会抛出 ClassNotFoundException 异常
public static void main(String[] args) {
Class<?> s3 = null;
try {
s3 = Class.forName("Student");//这里是类的全路径,如果有包需要加包的路径
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
注意:一个类在 JVM中只会有一个 Class 实例,那么也就是说上面我们获取的 s1、s2、s3 这些 Class 对象,其实都是一个 Class 对象
System.out.println(s1.equals(s2));
System.out.println(s1.equals(s3));
System.out.println(s2.equals(s3));
打印结果:
7、 反射的使用
我们目前已经知道了如何获取到一个类的Class实例,那么接下来我们就通过 Class 实例来进行反射的使用
我们还是使用上述的 Student 类来进行反射的使用
7.1 通过反射创建一个 Student 对象
1、通过公共构造方法创建对象
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
Class<?> studentClass = Student.class;//获取类的Class实例
Object objectStudent = studentClass.newInstance();//通过Class实例,创建一个对象
Student student = (Student) objectStudent;
System.out.println("获得的学生对象:"+student);
}
2、通过私有构造方法创建对象
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> studentClass = Student.class;
Constructor<?> declaredConstructorStudent = studentClass.getDeclaredConstructor(String.class,int.class);
declaredConstructorStudent.setAccessible(true);//设置为true后可修改访问权限
Object objectStudent = declaredConstructorStudent.newInstance("李四",18);
Student student = (Student)objectStudent;
System.out.println(student);
}
7.2 通过反射获取私有属性
public static void main(String[] args) throws IllegalAccessException, InstantiationException, NoSuchFieldException {
Class<?> studentClass = Student.class;
Field field = studentClass.getDeclaredField("name");
field.setAccessible(true);
Object objectStudent = studentClass.newInstance();
Student student = (Student)objectStudent;
String name = (String) field.get(student);
System.out.println(name);
}
7.3 通过反射获取私有方法
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InstantiationException, InvocationTargetException {
Class<?> studentClass = Student.class;
Method method = studentClass.getDeclaredMethod("function",String.class);
System.out.println("私有方法的方法名:"+method.getName());
method.setAccessible(true);
Object objectStudent = studentClass.newInstance();
Student student = (Student)objectStudent;
method.invoke(student,"私有方法的参数");
}
注:反射机制不能反射枚举