Java 泛型相关知识

什么是泛型?

Java 泛型(generics)是JDK5中引入的一种参数化类型特性。

为什么使用泛型,使用泛型的好处?

  1. 代码更健壮(只要编译期没有警告,那么运行期就不会出现 ClassCastException)
  2. 代码更简洁(不用强转)
  3. 代码更灵活,复用

什么是参数化类型:

  • 把类型当参数一样传递
  • <数据类型> 只能是引用类型(泛型的副作用)

举个例子:

public interface Plate<T> {
   
    
    
	public void set(T t);
	public T get();
}
public class ATPlate<T> implements Plate<T> {
   
    
    
	private List<T> items = new ArrayList<T>(10);

	public <T> ATPlate<T> getATPlate() {
   
    
    
		return new ATPlate<T>();
	}
}
  • Plate<T> 中的 "T” 称为类型参数,Plate<T> 整个称为泛型类型
  • Plate<Banana> 中的 “Banana” 称为实际类型参数, Plate<Banana> 整个称为参数化的类型ParameterizedType

泛型其实就是在类上面传参,可以类比方法传参,只不过类上面传的参数类型也只能是类。

泛型类型可以通过extends指定多个限定类型。

什么是多个限定类型,例如:

class A {
   
    
    }
interface B {
   
    
    }
interface C {
   
    
    }

// 具有多个限定的类型变量是范围中列出的所有类型的子类型。如果范围之一是类,则必须首先声明类
class D<T extends B & A & C> {
   
    
    } // 编译报错
class D<T extends A & B & C> {
   
    
    } // 编译OK

泛型擦除

Q:Java 泛型的原理?什么是泛型擦除机制?

  • Java 的泛型是 JDK5 引入的特性,为了向下兼容,虚拟机其实是不支持泛型,所以 Java 实现的是一种伪泛型机制,也就是说 Java 在编译期擦除了所有的泛型信息,这样 Java 就不需要产生新的类型到字节码所有的泛型类型最终都是一种原始类型在 Java 运行时根本就不存在泛型信息。

Q:Java 编译器具体是如何擦除泛型的?

  1. 检查泛型类型,获取目标类型
  2. 擦除类型变量,并替换为限定类型
    • 如果泛型类型的类型变量没有限定(<T>),则Object作为原始类型
    • 如果有限定(<T extends XCIass>),则XCIass作为原始类型
    • 如果有多个限定(T extends XCIass1 & XCIass2),则使用第一个边界XCIass1作为原始类型
  3. 在必要时插入类型转换以保持类型安全
  4. 生成桥方法以在扩展时保持多态性

例如,只有一个泛型 T 擦除后只有一个 Object 对象:

在这里插入图片描述
在这里插入图片描述

  • Basket<Fruit> 不存在于编译后的字节码

如果泛型有多个继承限定类型,则使用第一个限定类作为擦除后的类型,此外如果泛型类继承了支持泛型的接口,还会生成桥方法

在这里插入图片描述
在这里插入图片描述

如何通过反射获取泛型参数

泛型虽然被擦除了,但是在 类常量池 里面其实保留了泛型信息,所以可以通过反射获取泛型的信息 getGenericType()

Java 的泛型擦除并不是将所有泛型信息全部都擦除了,会将类上和方法上声明的泛型信息保存在字节码中的 Signature 属性中,这也是反射能够获取泛型的原因。但是在方法中的泛型信息是完全擦除了。

public class HelloWorld {
   
    
    
	Map<String, String> map;
	
	public static void main(String[] args){
   
    
     
		try {
   
    
    
			Field field = HelloWorld.class.getDeclaredField("map"); 
			Type type = field.getGenericType();
			System.out.println(type);// java.util.Map<java.lang.String, java.lang.String>
			System.out.println(type instanceof ParameterizedType); // true
			ParameterizedType pType = (ParameterizedType) type;
			System.out.print1n(pType.getRawType());// interface java.util.Map 
			for (Type argType : pType.getActualTypeArguments()) {
   
    
    
				System.out.println(argType); // class java.lang.String 
			}
			System.out.println(pType.getOwnerType()); // null
			
			Method method =HelloWorld.class.getMethod("applyMethod",Map.Entry.class); 
			Type[] types = method.getGenericParameterTypes();
			ParameterizedType pTypel = (ParameterizedType) types[0];
			System.out.println(pTypel.getOwnerType()); // interface java.util.Map 
			Map<String,String>[] maps = new Map[10];
			List<?>[] lists = new List

猜你喜欢

转载自blog.csdn.net/lyabc123456/article/details/134896174