泛型

本文详细介绍了Java泛型的概念,包括其基本定义、如何在方法和类中使用泛型,以及编译器处理泛型的方式。此外,还讲解了类型擦除的概念及其实现原理。

什么是泛型

Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。
泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。

怎么使用泛型

泛型方法

泛型方法,该方法在调用时可以接收不同类型的参数。根据传递给泛型方法的参数类型,编译器适当地处理每一个方法调用。

public <T> T doSth(T t){

}

泛型方法的规则:

  1. 所有泛型方法声明都有一个类型参数声明部分(由尖括号分隔),该类型参数声明部分在方法返回类型之前。

  2. 每一个类型参数声明部分包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。

  3. 类型参数能被用来声明返回值类型,并且能作为泛型方法得到的实际参数类型的占位符。

  4. 泛型方法体的声明和其他方法一样。注意类型参数只能代表引用型类型,不能是原始类型(int不行,Integer可以)。

泛型类

泛型类的声明和非泛型类的声明类似,除了在类名后面添加了类型参数声明部分。

和泛型方法一样,泛型类的类型参数声明部分也包含一个或多个类型参数,参数间用逗号隔开。一个泛型参数,也被称为一个类型变量,是用于指定一个泛型类型名称的标识符。因为他们接受一个或多个参数,这些类被称为参数化的类或参数化的类型。

 

public class Pair<K, V> implements Serializable{

}

编译器如何处理泛型

主流的编译器有2种处理泛型的方式:code specialization 和 code sharing。
  1. Code specialization。在实例化一个泛型类或泛型方法时都产生一份新的目标代码(字节码or二进制代码)。例如,针对一个泛型list,可能需要 针对string,integer,float产生List<String>, List<Integer>, List<Float>。
  2. Code sharing。对每个泛型类只生成唯一的一份目标代码;该泛型类的所有实例都映射到这份目标代码上,在需要的时候执行类型检查和类型转换。
    Code specialization 会为每个类型都产生一份执行代码,浪费空间 ,Java采用code sharing的方式来处理泛型。

类型擦除

类型擦除指的是通过类型参数合并,将泛型类型实例关联到同一份字节码上。编译器只为泛型类型生成一份字节码,并将其实例关联到这份字节码上。类型擦除的关键在于从泛型类型中清除类型参数的相关信息,并且再必要的时候添加类型检查和类型转换的方法。过程如下:
  1. 检查代码中的泛型类型
  2. 将所有泛型参数用它们的原始类型替换,例如:Object是最顶端的原始类型。
  3. 编译代码。

那么如何指定泛型的原始类型?

public class Pair<K extends Integer, V extends Serializable>{

}

上面的Pair泛型类就指定了参数的原始类型,K参数是Integer类型的,V参数是Number类型的。

问题来了,Serializable是接口,为什么是使用extends而不是implements?  这里的extends是用来做类型范围限制的,不是用于实现继承的特性。

extends A 表示泛型参数必须是A的子孙类,比如extends Number, 那么传入的泛型必须是Number的子类,比如Integer, Float等等

super A 表示泛型参数必须是A的父类, 比如super Integer, 那么传入的泛型必须是Integer的父类,比如Number, Object等

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值