泛型

本文围绕Java泛型展开,介绍了泛型类型擦除,即编译器编译带类型说明的集合时会擦除类型信息。还讲述了如何通过反射绕过编译器检查,探讨了参数化类型与原始类型的兼容性、泛型方法、泛型类的使用规则,以及如何通过反射获取泛型集合中的元素类型。

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

泛型类型擦除

jdk1.5提供了泛型这一新特性,它是给javac编译器使用的,可以限定集合中的输入类型,让编译器挡住原程序中的非法输入,编译器编译带类型说明的集合时会擦除类型信息,使程序运行效率不受影响。

        List<Integer> list1 = new ArrayList<>();
		List<String> list2 = new ArrayList<>();
		
		//运行时,list1、 list2被擦除为原始类型ArrayList
		System.out.println(list1.getClass());
		System.out.println(list2.getClass());

它们的输出结果都为 class java.util.ArrayList.

如果我们试图往list1中添加String类型的数据时,编译器会直接报错,因为list1使用了Integer类型的泛型限定,编译器会检查加入其中的元素是否为Integer类型。

如何绕过编译器

那有没有办法绕过编译器,这样就不会对list1中的类型进行检查,因而添加String类型的数据?
答案是肯定的,通过反射:

list1.getClass().getMethod("add",Object.class).invoke(list1, "abc");//这样编译器就不报错了,而且成功将字符串存入

因为对于参数化的泛型类型,getClass()返回值和原始类型一样,而且编译生成的字节码会进行泛型擦除,只要跳过编译器,就可以往泛型集合中加入其它类型的数据。

参数化类型与原始类型的兼容性

  • 参数化类型可以引用一个原始类型的对象,编译器报警告,例如:Collection < String> c = new ArrayList();
  • 原始类型可以引用一个参数化类型的对象,编译器报警告,例如:Collection c = new ArrayList< String>();

参数化类型不考虑类型参数的继承关系

  • List l = new ArrayList();//错误
  • List l = new ArrayList();//错误

泛型方法

只有引用类型才能作为泛型方法的实际参数!

private static <T> void swap(T[] a, int i, int j){
		T tmp = a[i];
		a[i] = a[j];
		a[j] = tmp;
	}
	
swap(new int[]{1,2,3},1,2);

此时编译器会报错,因为int是基本数据类型,不能作为实际参数传入。

但如果是这样:

private <T> void add(T a, T b){
		
	}
	
add(1,2);

编译器不会报错,我们可能会说,1,2也是基本数据类型啊,为何就可以?因为这里编译器会自动将其装箱成Integer类型。

多个泛型参数娶最大公约数
private static <T> void  f(T a, T b){

}

f(1,"111");

此时T取1跟"111"的最大公约数Object. T此时为Object类型。

泛型类

静态方法不能用泛型类的类型作为参数类型!

public class A<E>{
	public static void b(E e){
		
	}
}

这样写编译器会报错,b()是静态方法,不能用类的泛型作为参数类型。

获取泛型集合中的元素类型

给定一个泛型集合 List< String> list = new ArrayList<>(); 我们如何获取list中的泛型类型?
我们知道,java编译器编译后会将泛型擦除,因此无法知道其泛型类型

public class A {
	public void a(List<String> list){
		
	}
	
	public void a(List<Integer> list){
		
	}
}

像这样,编译器会报错,因为编译器会把 List跟List 看做同一类型,即List.
那么我们怎样获取泛型集合中的元素类型呢?

先给定一个方法,参数就是我们想要知道的泛型集合:

public static void applyList(List< Number> list){
		
	}

通过反射,获取applyList的参数List集合中的具体类型:

		//反射得到applyList()方法
		Method method = A.class.getMethod("applyList", List.class);
		//得到泛型参数类型数组
		Type[] types = method.getGenericParameterTypes();
		//applyList()中只有一个参数,因此取types[0]
		ParameterizedType  pType = (ParameterizedType) types[0];
		//通过ParameterizedType提供的方法打印类型
		System.out.println(pType.getActualTypeArguments()[0]);

结果输出为: class java.lang.Number

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

fastsy

打赏一份隆江猪脚饭吧

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

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

打赏作者

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

抵扣说明:

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

余额充值