Java范型与反射
Java的泛型是一种伪范型,意思是Java的范型其实只能在编译前有效,编译时编译器会擦除范型信息,因此也可能会出现一些范型导致的错误。
下面是一段经典的获取类型的代码
package reflect_test; /** * Created by dengxiaobing on 2018/6/9. */ public class Test<T> { public static void main(String[] args) { System.out.println(new Test<Number>().getClass()); } }
打印结果是
class reflect_test.Test
很明显,Java编译时已经把Test的范型参数Number擦除了
public static void main(String[] args) { System.out.println(new ArrayList<Integer>().getClass() == new ArrayList<String>().getClass()); }
这段代码的打印结果是true,表明Integer的List和String的List获取到的类类型是相同的,其实在编译后都是ArrayList<Object>,这就很尴尬了,有时候,我们确实想获取一个范型类的范型参数
这个时候,可以通过反射获取真正的范型参数
package reflect_test; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * Created by dengxiaobing on 2018/6/9. */ public class Test<T> { private static class Parent<T>{ } private static class Child extends Parent<Number>{ } public static void main(String[] args) { Type type = Child.class.getGenericSuperclass(); if (type instanceof ParameterizedType){ ParameterizedType parameterizedType = (ParameterizedType) type; Type[] types = parameterizedType.getActualTypeArguments(); for(Type t: types){ System.out.println(t.getTypeName()); } } } }
打印结果是
java.lang.Number
想象一下应用场景,在JPA中,我们继承一个JpaRepository就可以实现增删改查的操作了,增和改还好,需要传入一个Entity对象,可以通过这个Entity对象获取到类类型,然后通过类类型获取到注解和属性,再和数据库表做个ORM映射,就可以完成ORM操作了,但如果是查和删的操作,传入的是一个id之类的字段值,要获取类类型就需要获取范型参数了。通过上面 代码那种方式,在JpaRepository中的delete和search方法中用main方法中的操作获取到类类型,因为是继承,根据多态原理,实际的调用对象是子类的对象。
下面做一下简单的实现
package reflect_test; import java.lang.reflect.Field; import java.lang.reflect.ParameterizedType; import java.lang.reflect.Type; /** * Created by dengxiaobing on 2018/6/11. */ public class JPA_Test { private static class JpaRepository<ID,Entity>{ private Class getEntityClass(){ Type type = this.getClass().getGenericSuperclass(); if (type instanceof ParameterizedType){ ParameterizedType parameterizedType = (ParameterizedType) type; Type types[] = parameterizedType.getActualTypeArguments(); return types.length>1?((Class)types[1]):null; } return null; } void delete(ID id){ Class c = getEntityClass(); Field[] fields = c.getDeclaredFields(); for (Field field:fields){ System.out.println(field.getName()); } } Entity search(ID id){ return null; } } private static class Student{ private int id; private String name; private int age; } private static class StudentRepository extends JpaRepository<Integer,Student>{ } public static void main(String[] args) { JpaRepository<Integer,Student> repository = new StudentRepository(); repository.delete(0); } }
打印结果
id
name
age
得到了我们想到的信息
用这种技术就可以实现类似JPA的一个ORM框架了