Java-基础-泛型

本文详细介绍了Java泛型的四种类型:Type、ParameterizedType、TypeVariable和GenericArrayType,以及通配符WildCardType。通过示例展示了如何在反射中获取泛型信息,并解释了泛型擦除的原因。在框架开发中,泛型配合反射可以简化代码,提高代码的复用性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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>通过泛型加反射,初始化ViewBindingviewModel

Type ParameterizedType GenericArrayType TypeVariable WildcardType

1. Type

所有泛型类型的父接口,class 就是type

2. ParameterizedType

参数化类型,如Clollection<String>

  1. getActualTypeArguments(),获取此类型实际类型参数的Type对象的数组,如,比如Map<String,Boolean>,返回数组:String,Boolean
  2. getRawType(),可以返回当前类的信息对象(承载该泛型信息的对象类),比如List<String>,返回信息对象List
  3. getOwnerType(),返回是谁的成员,如果此类型为顶层类型,则返回 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

类型变量,各种类型变量的公共高级接口。

  1. gteBounds() 获取此类型的上边界,数组,如果没有上边界,默认object
  2. getGenericDeclaration , 此类型变量的一般声明
  3. 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类型。

  1. 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) {
    }
}
  1. 第一个参数List<String>[]的组成元素List<String>是ParameterizedType类型, 打印结果为true
  2. 第二个参数T[]的组成元素T是TypeVariable类型, 打印结果为true
  3. 第三个参数List<String>不是数组, 打印结果为false
  4. 第四个参数String[]的组成元素String是普通对象, 没有泛型, 打印结果为false
  5. 第五个参数int[] TypeArray的组成元素int是原生类型, 也没有泛型, 打印结果为false

5. WildcardType

该接口表示通配符泛型, 比如? extends Number 和 ? super Integer 它有如下方法:

  1. Type[] getUpperBounds(): 获取范型变量的上界
  2. 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TieJun~

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值