Java反射复习

Java反射概念

  类是由成员变量、方法、构造器组成,反射是把这些组成通过类的Class对象进行分别封装操作的过程。

  反射的操作是通过类的Class对象完成。

  注:下面代码示例基于jdk1.8,使用的是阿里开源的龙井jdk,dragonwell1.8.4

Java反射的优点

  直接操作Class,有统一的方法和步骤操作类的变量、方法、构造器,现在的反射代码,可以操作后期声明的类。

  为很多的设计思想提供了途径。

Java反射的缺点

  写代码更麻烦,性能下降,突破了权限带来安全问题

获取Class的3个方式

  1.Class.forName("包名.类名"),这个方式经常用于配置文件中。

Class.forName("com.mysql.cj.jdbc.Driver")

   2.类名.class,该方法经常用于方法参数

User user = BeanUtils.copyProperties(u,User.class);

  3.对象.getClass(),该方法经常用于获取对象字节码

Logger log = LoggerFactory.getLogger(this.getClass());

 Class对象的使用

  Class在Java程序中只会加载一份到内存,上面三个方法获取的Class对象都是同一个内存地址,多次获取也是同一个对象。

  Class源码中可以看到,Class对象是由Java虚拟机加载

   如下BaseEntity和User类来测试使用Class

 1 import java.util.Date;
 2 
 3 public class BaseEntity {
 4     public Date time;
 5     private int status;
 6 
 7     public Date getTime() {
 8         return time;
 9     }
10 
11     public void setTime(Date time) {
12         this.time = time;
13     }
14 
15     public int getStatus() {
16         return status;
17     }
18 
19     public void setStatus(int status) {
20         this.status = status;
21     }
22 }
BaseEntity
 1 public class User extends BaseEntity {
 2     long id;
 3     private String name;
 4     public String email;
 5     protected int age;
 6 
 7     public String read(){
 8         return "我在看书";
 9     }
10 
11     private String watch(){
12         return "我在看电视";
13     }
14 
15     public User() {
16     }
17 
18     public User(long id, String name, String email, int age) {
19         this.id = id;
20         this.name = name;
21         this.email = email;
22         this.age = age;
23     }
24 
25     public long getId() {
26         return id;
27     }
28 
29     public void setId(long id) {
30         this.id = id;
31     }
32 
33     public String getName() {
34         return name;
35     }
36 
37     public void setName(String name) {
38         this.name = name;
39     }
40 
41     public String getEmail() {
42         return email;
43     }
44 
45     public void setEmail(String email) {
46         this.email = email;
47     }
48 
49     public int getAge() {
50         return age;
51     }
52 
53     public void setAge(int age) {
54         this.age = age;
55     }
56 }
User

Class的Field

 1 org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(this.getClass());
 2     Class cls = User.class;
 3 
 4     @Test
 5     public void testClassGetField() throws Exception {
 6         /**
 7          * 结论:
 8          *   1. getField("xxx")/ getFields()
 9          *    只能获取 public修饰的成员变量,包括父类的public成员变量
10          *   2. getDeclaredField("xxx")/getDeclaredFields()
11          *     能获取当前类声明的成员变量,无视修饰符,但不包括父类的成员变量
12          */
13         //× default修饰 抛出异常,java.lang.NoSuchFieldException: name
14         Field idField = cls.getField("id");
15         //× private修饰 抛出异常,java.lang.NoSuchFieldException: name
16         Field nameField = cls.getField("name");
17         //√ public修饰 正常执行,可以获取public成员变量
18         Field emailField = cls.getField("email");
19         //× protected修饰 抛出异常 ,java.lang.NoSuchFieldException: age
20         Field ageField = cls.getField("age");
21         //√ public修饰 正常执行,可以获取 父类 public成员变量
22         Field timeField = cls.getField("time");
23         //× private修饰 抛出异常 ,java.lang.NoSuchFieldException: status
24         Field statusField = cls.getField("status");
25 
26         // 只能获取public修饰的成员变量列表
27         Field[] fields = cls.getFields();
28         for (Field field : fields) {
29             log.info("array--field = {}", field);
30         }
31 
32         // cls.getDeclaredField("xxx") 都能获取xxx对应的成员变量
33         Field idDeclaredField = cls.getDeclaredField("id");
34         Field nameDeclaredField = cls.getDeclaredField("name");
35         Field emailDeclaredField = cls.getDeclaredField("email");
36         Field ageDeclaredField = cls.getDeclaredField("age");
37         //父类的不能 抛出异常,java.lang.NoSuchFieldException: time
38         Field timeDeclaredField = cls.getDeclaredField("time");
39         //父类的不能 抛出异常,java.lang.NoSuchFieldException: status
40         Field statusDeclaredField = cls.getDeclaredField("status");
41 
42         // 都能获取所有成员变量
43         Field[] declaredFields = cls.getDeclaredFields();
44         for (Field field : declaredFields) {
45             log.info("array--declared field = {}", field);
46         }
47 
48     }
getField
 1    @Test
 2     public void testClassOperateFields() throws Exception {
 3         /**
 4          * 结论:
 5          *  1.Field对象可以获取和修改成员变量的值
 6          *  2.非public修饰的成员变量,获取和修改前需要获取权限
 7          */
 8         // cls反射创建User对象,需要有public的无参构造方法
 9         User user = (User) cls.newInstance();
10         Field emailField = cls.getField("email");
11         log.info("email1 = {}",emailField.get(user));
12         emailField.set(user,"1@qq.com");
13         // field获取成员变量的值,传参是对应对象
14         log.info("email2 = {}",emailField.get(user));
15         log.info("email2 = {}",user.getEmail());
16 
17         Field emailDeclaredField = cls.getDeclaredField("email");
18         emailDeclaredField.set(user,"2@qq.com");
19         log.info("email3 = {}",user.getEmail());
20 
21         Field idDeclaredField = cls.getDeclaredField("id");
22         log.info("id1 = {}",user.getId());
23         //异常 java.lang.IllegalAccessException
24         log.info("id1 = {}",idDeclaredField.get(user));
25         //异常 java.lang.IllegalAccessException
26         idDeclaredField.set(user,9);
27         // 非public修饰的成员变量需要设置权限
28         idDeclaredField.setAccessible(true);
29         idDeclaredField.set(user,10);
30         log.info("id2 = {}",user.getId());
31         log.info("id2 = {}",idDeclaredField.get(user));
32 
33     }
operateField

Class的Method 

 1 @Test
 2     public void testGetClassMethods() throws Exception {
 3         /**
 4          * 结论:
 5          * 1.获取单个方法,需要方法名+参数列表类型按顺序排列
 6          *      getMethod("xxx",xx.class,xx.class..)
 7          * 2.有Declared修饰的方法可以获取当前类所有方法,无视修饰符
 8          *       仅限当前类,不包括父类
 9          * 3.没有Declared修饰的只能获取public修饰的方法
10          *        父类,都可以获得
11          */
12         Method setIdMethod = cls.getMethod("setId", long.class);
13         log.info("setIdMethod = {}",setIdMethod);
14         //异常 java.lang.NoSuchMethodException
15         Method watchMethod = cls.getMethod("watch");
16         Method[] methods = cls.getMethods();
17         for (Method method : methods){
18             log.info("methods = {}",method);
19         }
20 
21         Method setIdDeclaredMethod = cls.getDeclaredMethod("setId", long.class);
22         log.info("setIdDeclaredMethod = {}",setIdDeclaredMethod);
23         Method watchDeclaredMethod = cls.getDeclaredMethod("watch");
24         log.info("watchDeclaredMethod = {}",watchDeclaredMethod);
25 
26         Method[] declaredMethods = cls.getDeclaredMethods();
27         for (Method method : declaredMethods){
28             log.info("declared = {}",method);
29         }
30         
31     }
getMethod
 1  @Test
 2     public void testUseClassMethod() throws Exception {
 3         /**
 4          * 和Field使用相似,明显区别是确定方法需要方法名+参数列表
 5          * 执行非public方法需要授权
 6          * invoke执行方法和对象.方法的结果一样
 7          */
 8         User user = (User) cls.newInstance();
 9         Method setIdMethod = cls.getMethod("setId", long.class);
10         log.info("id1 = {}",user.getId());
11         // 执行方法,对象+参数列表
12         setIdMethod.invoke(user,121);
13         log.info("id2 = {}",user.getId());
14 
15         Method readMethod = cls.getMethod("read");
16         Object readResult = readMethod.invoke(user);
17         log.info("readResult = {}",readResult);
18 
19         Method watchMethod = cls.getDeclaredMethod("watch");
20         //private修饰 执行异常 java.lang.IllegalAccessException
21         watchMethod.invoke(user);
22         // 需要授权
23         watchMethod.setAccessible(true);
24         Object watchResult = watchMethod.invoke(user);
25         log.info("watchResult = {}",watchResult);
26 
27     }
useMethod

Class的Constructor

    结论:不需要方法名以外,和Method相似,newInstance返回值是类的对象

Class类还有很多内容,有用到再去了解了,有兴趣的可以去看java.lang.Class源码

  

 

posted @ 2020-11-17 17:43  面包和牛奶  阅读(21)  评论(0)    收藏  举报