Java 反射机制

什么是反射机制

Java的反射(reflection)机制是指在程序的运行状态中,可以构造任意一个类的对象,可以了解任意一个对象所属的类,可以了解任意一个类的成员变量和方法,可以调用任意一个对象的属性和方法。这种动态获取程序信息以及动态调用对象的功能称为Java语言的反射机制。反射被视为动态语言的关键(在运行阶段可以改变其结构)

特点:

1、极大的提高了程序的灵活性和扩展性,降低模块的耦合性,提高自身的适应能力

2、通过反射机制可以让程序创建和控制任何类的对象,无需提前硬编码目标类

3、能够在运行时构造一个类的对象、判断一个类所具有的成员变量和方法、调用一个对象的方法(包括 private),可能会有安全隐患

4、是构建框架技术的基础所在,使用反射可以避免将代码写死在框架中

5、包含动态类型,而 JVM 不能对动态代码优化,所以效率会比较低

 

在Java中可以通过Reflection APIs在运行时动态生成class实体,通过Constructor创建类实例、Field访问成员属性、Method调用方法

Class类

在Java中,每个 class 都有一个相应的 Class 对象。在编译完成后,在生成的.class文件中,会产生一个Class对象,用于表示这个类的类型信息。

特点:

1、由系统创建Class类

2、同一个类的实例指向同一个Class对象

3、通过Class可以完整的得到一个类所有被加载的结构

4、Class类是Java反射的基础

获得Class类的方法:

 1 public class MyReflect {
 2     public static void main(String[] args) throws ClassNotFoundException {
 3         Teacher t = new Teacher();
 4         // 1、通过对象获得
 5         Class c1 = t.getClass();
 6         // 2、forName + 全限定名 获得
 7         Class c2 = Class.forName("reflect.Teacher");
 8         // 3、通过类名获得
 9         Class c3 = Teacher.class;
10         // 4、基本数据类型的Type属性获得
11         Class c4 = Double.TYPE;
12         // 5、通过子类的Class对象获得
13         Class c5 = c1.getSuperclass();
14     }
15 }
16 class Person {
17     String name;
18     public Person() {
19     }
20 }
21 class Teacher extends Person {
22     public Teacher() {
23     }
24 }
View Code

 

getXXX为获取 public 构造器、属性、方法

getDeclaredXXX 获取任意构造器、属性、方法(包括private)

setAccessible方法避开权限检测,用以访问权限不足的成员

以下不在赘述

准备:Person类以及Tercher子类

 1 package reflect;
 2 
 3 class Person {
 4     public String name;
 5     private int age;
 6 
 7     public String getName() {
 8         return name;
 9     }
10 
11     public void setName(String name) {
12         this.name = name;
13     }
14 
15     public int getAge() {
16         return age;
17     }
18 
19     public void setAge(int age) {
20         this.age = age;
21     }
22 
23     public Person() {
24     }
25 
26     public Person(String name, int age) {
27         this.name = name;
28         this.age = age;
29     }
30 
31     @Override
32     public String toString() {
33         return "Person{" +
34                 "name='" + name + '\'' +
35                 ", age=" + age +
36                 '}';
37     }
38 
39     public String greet(String name) {
40         return "hello " + name + ".";
41     }
42 }
43 
44 class Teacher extends Person {
45 
46 }
View Code

Constructor类

java.lang.reflect.Constructor类是java.lang.reflect.Executable类的直接子类,用于表示类的构造方法。通过Class对象的 getConstructors() 方法可以获得当前运行时类的构造方法

 1 public class MyConstructor {
 2     public static void main(String[] args) throws Exception {
 3         Class<Person> c = (Class<Person>) Class.forName("reflect.Person");
 4 
 5 //        Object person2 = c.newInstance();   //@Deprecated
 6 //        System.out.println(person2);
 7         Constructor<Person> constructor = c.getConstructor();
 8         Person person = constructor.newInstance();
 9         System.out.println(person);
10 
11         // 获取 public 有参构造方法
12         Constructor<Person> constructor1 = c.getConstructor(String.class, int.class);
13         Person person1 = constructor1.newInstance("JL", 18);
14         System.out.println(person1);
15         
16         // 获取构造方法
17         Constructor<Person> constructor2 = c.getDeclaredConstructor(String.class, int.class);
18         constructor2.setAccessible(true);
19         Person person2 = constructor1.newInstance("JL", 18);
20         System.out.println(person2.name);
21     }
22 }
View Code

Field类

java.lang.reflect.Field类用于封装成员变量信息,调用Class对象的 getField()getFields() 等方法可以获得当前运行时类的成员变量

 1 public class MyField {
 2     public static void main(String[] args) throws Exception {
 3         Class<?> c = Class.forName("reflect.Person");
 4         // 在Person类中,无参的构造方法不能省略
 5         Object p = c.getConstructor().newInstance();
 6 
 7         // 获取 public 成员变量
 8         Field[] fields = c.getFields();
 9         // 获取所有成员变量(包括 private)
10         Field[] allFields = c.getDeclaredFields();
11         //获取指定名称public变量
12         Field f1 = c.getField("name");
13         // 成员变量set、get
14         f1.set(p, "JL");
15         System.out.println(f1.get(p));
16 
17         Field f2 = c.getDeclaredField("age");   // private int age
18         // 忽略权限检查,使得 private 成员可以被访问
19         f2.setAccessible(true);
20         f2.set(p, 18);
21         System.out.println(f2.get(p));
22     }
23 }
View Code

Method类

java.lang.reflect.Method类是java.lang.reflect.Executable类的直接子类,用于封装成员方法的信息,调用Class对象的 getMethod() 方法或 getMethods() 方法可以获得当前运行时类的指定方法或所有方法

 1 public class MyMethod {
 2     public static void main(String[] args) throws Exception {
 3         Class<Person> c = (Class<Person>) Class.forName("reflect.Person");
 4         Person p = c.getConstructor().newInstance();
 5         // 获取所有 public 方法
 6         Method[] methods = c.getMethods();
 7         // 获取 greet 方法
 8         Method method1 = c.getMethod("greet", String.class);
 9         //执行 greet 方法
10         System.out.println(method1.invoke(p, "JL"));
11     }
12 }
View Code0

PS:主要简单说明反射的使用,关于类加载机制,性能分析等没有说明

posted @ 2020-07-26 22:25  whyha  阅读(179)  评论(0)    收藏  举报