当前位置: 代码迷 >> 综合 >> Java反射初探
  详细解决方案

Java反射初探

热度:77   发布时间:2024-02-13 16:50:18.0

一、什么是反射?

在运行状态中,对于任意一个类,都能获取到这个类的所有属性和方法,对于任意一个对象,都能够调用它的任意一个方法和属性(包括私有的方法和属性),这种动态获取的信息以及动态调用对象的方法的功能就称为Java的反射机制。简单来讲,通过反射,该类对我们来说就是完全透明的,想要获取任何东西都可以。

想要使用反射机制,就必须要先获取到该类的字节码对象(.class),通过字节码对象文件,就能够通过该类中的方法获取到我们想要的信息(方法、属性、类名、父类名,实现的所有接口等等),每一个类对应着一个字节码文件也就对应着一个Class类型的对象,也就是字节码文件对象。

1、获取字节码对象的3种方式

(1) 通过Class类中的静态方法forName()直接获取到一个类的字节码文件对象

 例: Class<?> aClass = Class.forName("com.example.homework.model.entity.Person");

 即可获取到Person类的字节码对象

(2)通过类自身获取

Class<Person> p2Class = Person.class;

(3)通过类的实例获取字节码对象

Person person = new Person();
Class<? extends Person> p3Class = person.getClass();

二、通过反射获取我们需要的信息

通过字节码对象创建实例

通过反射获取实例对象,直接使用字节码对象newInstance()即可创建一个实例

Class<Person> p2Class = Person.class;

Person p2 = p2Class.newInstance();

获取属性

获取所有的属性,不包含私有属性:   Field[] fields = p2Class.getFields();

获取特定的属性,不包含私有属性:   Field pai = p2Class.getField("pai");

如果需要获取私有的属性需要使用下面的api

Field[] declaredFields = p2Class.getDeclaredFields();

Field idField = p2Class.getDeclaredField("id");

获取方法:

我们首先列出Person类中的两个测试方法:

//  公有方法public String test1(){System.out.println("test1,已经执行了!");return "hello world!";}
//    私有方法private String privateTest2(String name,Double d){System.out.println(name+"你好;工资:"+d);return "hello"+name;}

获取类的方法(不包含私有方法)并调用:

Method m1 = p2Class.getMethod("test1");m1.invoke(p2);

这里为一个无参的方法,调用时无需指定参数类型,如果是有参方法,是需要明确指定参数类型的,

获取类的私有方法,且该方法有参数:

        Method privateTest2 = p2Class.getDeclaredMethod("privateTest2", String.class, Double.class);privateTest2.setAccessible(true);privateTest2.invoke(p2,"alice",900.85);result:alice你好;工资:900.85  

三、应用

 springdata jpa 中构造自定义转换类的时候,通过SQL查询出来的别名可以和我们的实体类对应,并在transformTuple中构建一个实体类,该实体类的属性即为SQL查询出来的字段,值是统计出来的结果,

public class DefineResultTransformer<T> implements ResultTransformer, Serializable {private static final long serialVersionUID = 775781526148172513L;private Class<T> resultClazz;private BeanUtilsBean beanUtilsBean;public DefineResultTransformer(Class<T>  resultClass){this.resultClazz = resultClass;this.beanUtilsBean = BeanUtilsBean.getInstance();}@Overridepublic Object transformTuple(Object[] tuple, String[] aliases) {Object result = null;Field[] fields = resultClazz.getDeclaredFields();try {result = resultClazz.newInstance();for(int i =0 ;i<aliases.length; i++){for(Field field : fields){
//   1、忽略大小写映射,如SQL查询字段为 "username" 可直接映射为Java实体类中userName属性
//   2、去掉"_" 映射,如SQL查询出的字段为 "user_name" 也可直接映射为Java实体类中userName属性if(field.getName().equalsIgnoreCase(aliases[i].replaceAll("_",""))){beanUtilsBean.setProperty(result,field.getName(),tuple[i]);break;}}}} catch (Exception e) {e.printStackTrace();}return result;}@Overridepublic List transformList(List collection) {return collection;}}

该工具方法转换类,接收一个结果类的字节码对象,然后通过反射获取该对象的属性,并和SQL查询查来的别名以及结果封装数据构造对象,最终完成SQL查询结果到Java对象的转换。