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 }
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 }
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 }
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 }
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 }
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 }
Class的Constructor
结论:不需要方法名以外,和Method相似,newInstance返回值是类的对象
Class类还有很多内容,有用到再去了解了,有兴趣的可以去看java.lang.Class源码

浙公网安备 33010602011771号