反射
Posted 蓝雨晴天
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射相关的知识,希望对你有一定的参考价值。
1、什么是反射
反射是指在程序的运行状态中,可以获取任意一个类的全部信息(包括类名、类的字段、类的属性、类的方法等等),可以获取任意一个对象所属的类,并且可以调用对象的任意方法和属性。
简单来说,反射就是一开始我们并不知道要初始化的类对象是什么,所以就不能通过正常的new的方式来实例化一个对象,需要通过反射的方式加载指定的Class文件,然后再实例化对象,进行其他操作。
2、Person类
示例程序,方便后续举例说明。
package com.zhangh.reflect;
public class Person {
public String name = "zhangh";
protected Integer age = 1;
private Byte sex = (byte) 1;
Boolean isMarriage = true;
public Person() {
}
public Person(String name, Integer age, Byte sex, Boolean isMarriage) {
this.name = name;
this.age = age;
this.sex = sex;
this.isMarriage = isMarriage;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Byte getSex() {
return sex;
}
public void setSex(Byte sex) {
this.sex = sex;
}
public Boolean getMarriage() {
return isMarriage;
}
public void setMarriage(Boolean marriage) {
isMarriage = marriage;
}
@Override
public String toString() {
return "Person{" +
"name=\'" + name + \'\\\'\' +
", age=" + age +
", sex=" + sex +
", isMarriage=" + isMarriage +
\'}\';
}
}
3、Class文件
class文件包含了一个类的所有的信息,如下图所示:
4、获取Class对象的方式
-
类名.class
Class personClazz = Person.class;
-
Class.forName
Class personClazz = Class.forName("com.zhangh.Person");
-
getClass方式
Person person = new Person(); Class personClazz = person.getClass();
5、反射关键类图
6、类加载区别
7、生成对象的步骤
8、简单示例
package com.zhangh.reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class Test {
public static void main(String[] args) throws Exception{
// 获取Class类对象
Class personClazz = Class.forName("com.zhangh.reflect.Person");
// 获取无参构造方法
Constructor constructor1 = personClazz.getConstructor();
// 通过无参构造方法创建对象
Object person1 = constructor1.newInstance();
// 获取age属性
Field field = personClazz.getDeclaredField("age");
// 设置person对象的age属性
field.set(person1,25);
// 获取setName方法
Method method = personClazz.getDeclaredMethod("setName",String.class);
// 执行setName方法,为person1对象设置名称为test
method.invoke(person1,"test");
System.out.println(person1);
// 也可以通过有参构造方法创建对象
Constructor constructor2 = personClazz.getConstructor(String.class,Integer.class,Byte.class,Boolean.class);
Object person2 = constructor2.newInstance("zhangsan",30,(byte)1,true);
System.out.println(person2);
}
}
9、反射中的常用方法
方法名 | 描述 | 代码示例 |
---|---|---|
getName | 获取类名(包含全路径) | String name = personClazz.getName(); |
getSimpleName | 获取类名(不包含路径) | String simpleName = personClazz.getSimpleName(); |
getPackage | 获取包名 | String package = personClazz.getPackage(); |
getSuperClass | 获取父类 | Class superClass = personClazz.getSuperClass(); |
getInterfaces | 获取所有父接口 | Class[] interfaces = personClazz.getInterfaces(); |
newInstance | 调用默认的无参构造,创建对象 | Object obj = personClazz.newInstance(); |
getFields | 获取所有的公有属性,包括继承的父类属性 | Field[] fields = personClazz.getFields(); |
getField | 获取指定的某个公有属性,包括继承的父类属性 | Field field = personClazz.getField("age"); |
getDeclareFields | 获取所有的属性,包括私有属性,但是不能获取到父类的属性 | Field[] fields = personClazz.getDeclareFields(); |
getDeclareField | 获取指定的某个属性,包括私有属性,但是不能获取到父类的属性 | Field field = personClazz.getDeclareField("age"); |
10、反射的应用
反射的出现,大大增强了程序的灵活性和扩展性,在很多场景都使用到了反射,尤其是很多框架里,以下简单举几个例子。
-
Servlet接口
每个Web应用程序都有自己的配置文件web.xml,可以在其中配置Servlet的实现类,包含名称、类路径、url等信息。Web容器会读取web.xml中配置的servlet信息,根据类路径,加载对应的Class文件到jvm中。
-
Spring
Spring的很多地方都使用到了反射技术,例如通过xml配置的方式来装载bean。
11、BeanUtils工具类
通过反射来封装一个工具类,将一个对象的属性的值,赋值给另外一个属性名相同的对象,可以理解为是对象的拷贝。
package com.zhangh.reflect;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
public class BeanUtils {
public static void convertor(Object originObj, Object targetObj) throws Throwable{
// 第一步,获得class对象
Class orginClazz = originObj.getClass();
Class targetClazz = targetObj.getClass();
// 第二步,获得Field
Field[] orginFields = orginClazz.getDeclaredFields();
Field[] targetFields = targetClazz.getDeclaredFields();
Map<String,Field> orginMap = new HashMap<>();
Map<String,Field> targetMap = new HashMap<>();
for(Field field : orginFields){
field.setAccessible(true);
orginMap.put(field.getName(),field);
}
for(Field field : targetFields){
field.setAccessible(true);
targetMap.put(field.getName(),field);
}
// 第三步,赋值
for(String key : orginMap.keySet()){
if(targetMap.containsKey(key)){
targetMap.get(key).set(targetObj,orginMap.get(key).get(originObj));
}
}
/* // 第三步:赋值,能实现同样的效果,但是多次循环,效率比较低
for (Field originField : orginFields) {
for (Field targetField : targetFields) {
if (originField.getName().equals(targetField.getName())) {
originField.setAccessible(true);
targetField.setAccessible(true);
targetField.set(targetObj, originField.get(originObj));
}
}
}*/
}
public static void main(String[] args) throws Throwable{
Person person = new Person("zhangh", 10, (byte)1, true);
Person person1 = new Person();
convertor(person, person1);
System.out.println("person:" + person);
System.out.println("person1:" + person1);
}
}
以上是关于反射的主要内容,如果未能解决你的问题,请参考以下文章