Java 泛型
文章目录
Java 泛型有三种:泛型类、泛型方法、泛型接口
Java Type类型有:原始类型(raw types ,class),参数化类型(parameterized type,ParameterizedType),数组类型(array types,GenericArrayType),类型变量(type varalbes, TypeVariable),通配符泛型(WildcardType)
在框架搭建时,泛型配合反射,减少代码,通过在
BaseActivity<VM>
中是能够拿到泛型的原始信息的,通过反射初始化出来viewModel
,通过这种方式,我们利用泛型的能力,基类包办了所有的初始化任务,不但逻辑简单,而且也体现了高内聚,在实际项目中可以使用。
例子,
class BaseBindingActivity<VM : BaseViewModel, VB : ViewBinding>
通过泛型加反射,初始化ViewBinding
和viewModel
1. Type
所有泛型类型的父接口,class 就是type
2. ParameterizedType
参数化类型,如Clollection<String>
getActualTypeArguments()
,获取此类型实际类型参数的Type
对象的数组,如,比如Map<String,Boolean>
,返回数组:String,BooleangetRawType()
,可以返回当前类的信息对象(承载该泛型信息的对象类),比如List<String>
,返回信息对象ListgetOwnerType()
,返回是谁的成员,如果此类型为顶层类型,则返回 null(大多数情况都是这样)
public class TestType {
Map<String, String> map;
public static void main(String[] args) throws Exception {
Field f = TestType.class.getDeclaredField("map");
System.out.println(f.getGenericType()); // java.util.Map<java.lang.String, java.lang.String>
System.out.println(f.getGenericType() instanceof ParameterizedType); // true
ParameterizedType pType = (ParameterizedType) f.getGenericType();
System.out.println(pType.getRawType()); // interface java.util.Map
for (Type type : pType.getActualTypeArguments()) {
System.out.println(type); // 打印两遍: class java.lang.String
}
System.out.println(pType.getOwnerType()); // null
}
}
3.TypeVarialbe
类型变量,各种类型变量的公共高级接口。
gteBounds()
获取此类型的上边界,数组,如果没有上边界,默认objectgetGenericDeclaration
, 此类型变量的一般声明getName()
,获取源码定义的名字
public class TestType <K extends Comparable & Serializable, V> {
K key;
V value;
public static void main(String[] args) throws Exception {
// 获取字段的类型
Field fk = TestType.class.getDeclaredField("key");
Field fv = TestType.class.getDeclaredField("value");
Assert.that(fk.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
Assert.that(fv.getGenericType() instanceof TypeVariable, "必须为TypeVariable类型");
TypeVariable keyType = (TypeVariable)fk.getGenericType();
TypeVariable valueType = (TypeVariable)fv.getGenericType();
// getName 方法
System.out.println(keyType.getName()); // K
System.out.println(valueType.getName()); // V
// getGenericDeclaration 方法
System.out.println(keyType.getGenericDeclaration()); // class com.test.TestType
System.out.println(valueType.getGenericDeclaration()); // class com.test.TestType
// getBounds 方法
System.out.println("K 的上界:"); // 有两个
for (Type type : keyType.getBounds()) { // interface java.lang.Comparable
System.out.println(type); // interface java.io.Serializable
}
System.out.println("V 的上界:"); // 没明确声明上界的, 默认上界是 Object
for (Type type : valueType.getBounds()) { // class java.lang.Object
System.out.println(type);
}
}
}
4.GenericArrayType
(一般是参数)
泛型数组,组成数组的元素中泛型需要实现了该接口;它的组成元素是ParameterizedType或TypeVariable类型。
getGenericComponentType()
返回数组对象
public class TestType <T> {
public static void main(String[] args) throws Exception {
Method method = Test.class.getDeclaredMethods()[0];
// public void com.test.Test.show(java.util.List[],java.lang.Object[],java.util.List,java.lang.String[],int[])
System.out.println(method);
Type[] types = method.getGenericParameterTypes(); // 这是 Method 中的方法
for (Type type : types) {
System.out.println(type instanceof GenericArrayType);
}
}
}
class Test<T> {
public void show(List<String>[] pTypeArray, T[] vTypeArray, List<String> list, String[] strings, int[] ints) {
}
}
- 第一个参数
List<String>[]
的组成元素List<String>
是ParameterizedType类型, 打印结果为true - 第二个参数T[]的组成元素T是TypeVariable类型, 打印结果为true
- 第三个参数
List<String>
不是数组, 打印结果为false - 第四个参数
String[]
的组成元素String是普通对象, 没有泛型, 打印结果为false - 第五个参数
int[] TypeArray
的组成元素int是原生类型, 也没有泛型, 打印结果为false
5. WildcardType
该接口表示通配符泛型, 比如? extends Number 和 ? super Integer 它有如下方法:
Type[] getUpperBounds()
: 获取范型变量的上界Type[] getLowerBounds()
: 获取范型变量的下界
public class TestType {
private List<? extends Number> a; // a没有下界, 取下界会抛出ArrayIndexOutOfBoundsException
private List<? super String> b;
public static void main(String[] args) throws Exception {
Field fieldA = TestType.class.getDeclaredField("a");
Field fieldB = TestType.class.getDeclaredField("b");
Assert.that(fieldA.getGenericType() instanceof ParameterizedType, "");
Assert.that(fieldB.getGenericType() instanceof ParameterizedType, "");
ParameterizedType pTypeA = (ParameterizedType) fieldA.getGenericType();
ParameterizedType pTypeB = (ParameterizedType) fieldB.getGenericType();
Assert.that(pTypeA.getActualTypeArguments()[0] instanceof WildcardType, "");
Assert.that(pTypeB.getActualTypeArguments()[0] instanceof WildcardType, "");
WildcardType wTypeA = (WildcardType) pTypeA.getActualTypeArguments()[0];
WildcardType wTypeB = (WildcardType) pTypeB.getActualTypeArguments()[0];
// 方法测试
System.out.println(wTypeA.getUpperBounds()[0]); // class java.lang.Number
System.out.println(wTypeB.getLowerBounds()[0]); // class java.lang.String
// 看看通配符类型到底是什么, 打印结果为: ? extends java.lang.Number
System.out.println(wTypeA);
}
}
6.一些例子
比如 ClassA<T>
,ClassB<T>
中<T>
;
可以通过 getActualTypeArguments()
得到具体的类型
例如:
(obj.javaClass as ParameterizedType).actualTypeArguments[0] as Class<C>
其他:
this.methodAnnotations = method.getAnnotations(); //获取方法的注解
this.parameterTypes = method.getGenericParameterTypes();//获取方法中所有参数的类型
this.parameterAnnotationsArray = method.getParameterAnnotations();//获取参数的注解类型
1,当我们拿到一个Class,用Class. getGenericInterfaces()方法得到Type[],
也就是这个类实现接口的Type类型列表。
2,当我们拿到一个Class,用Class.getDeclaredFields()方法得到Field[],
也就是类的属性列表,然后用Field. getGenericType()方法得到这个属性的Type类型。
3,当我们拿到一个Method,用Method. getGenericParameterTypes()方法获得Type[],
也就是方法的参数类型列表
4. 当我们拿到一个class ,用getActualTypeArguments() 得到这个类的具体泛型<>,
7.产生泛型擦除的原因
原始类型和新产生的类型都应该统一成各自的字节码文件类型对象。
但是由于泛型不是最初Java中的成分,泛型是1.5
才引进的。
如果真的加入了泛型,涉及到JVM指令集的修改,这是非常致命的。
所有编译器javac
会把所有泛型进行擦除
public void test(List infoList) {}
public void test(List<Info> infoList) { }
泛型擦除编译器报错了,“ both methods has the same erasure” 这个错误提示,
所以作为泛型擦除的补偿,Java引入了通配符
如果需要一个只读的泛型集合,使用?extends T
如果需要一个只写的泛型集合,使用?super T