文章目录
- 1. 泛型
- 1.1 泛型的实现
- 1.2 泛型的好处
- 1.3 泛型的用途
- 1.4 小结
- 2. 常用通配符
- 2.1 理解通配符
- 2.2 总结
1. 泛型
Java 泛型(generics)是 JDK 5 中引入的一个新特性, **泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。**泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
1.1 泛型的实现
Java 的泛型是伪泛型,这是因为 Java 在编译期间,所有的泛型信息都会被擦掉,这也就是通常所说类型擦除 。
Java在编译后的字节码(.class)文件中是不包含泛型中的类型信息的,使用泛型的时候加上的类型参数,会被编译器在编译的时候去掉,这个过程就称为类型擦除。
如在代码中定义的List<Object>
和List<String>
等类型,在编译之后都会变成List,JVM看到的只是List,而由泛型附加的类型信息对JVM来说是不可见的。 因此,对于JVM来说,List<Object>
和List<String>
就是同一个类,所以,泛型实际上是Java语言的一个语法糖,又被叫做伪泛型。
而C++的泛型则来源于C++引入的STL模板,而STL模板是一套编译时多态技术,会在编译时针对不同的模板参数静态实例化,生成大量代码,运行速度会快很多,是图灵完备的(图灵完全性通常指具有无限存储能力的通用物理机器或编程语言)。
1.2 泛型的好处
- 提交了java的类型安全
泛型在很大程度上来提高了java的程序安全。例如在没有泛型的情况下,很容易将字符串 123 转成 Integer 类型的 123 亦或者 Integer 转成 String,而这样的错误是在编译期无法检测。而使用泛型,则能很好的避免这样的情况发生。 - 不需要烦人的强制类型转换
泛型之所以能够消除强制类型转换,那是因为程序员在开发的时候就已经明确了自己使用的具体类型,这不但提高了代码的可读性,同样增加了代码的健壮性。 - 提高了代码的重用性:泛型的程序设计,意味着编写的代码可以被很多不同类型的对象所重用
// 不适用泛型
Pair p = new Pair("string",222);
String key = (String) p.getKey(); // 正常
String value = (String) p.getValue(); // 编译时报错
// 使用泛型
Pair<String,Integer> p = new Pair("string",222);
String key = (String) p.getKey(); // 正常
String value = (String) p.getValue(); // 在编译之前,编译器就会报错:无法转换
1.3 泛型的用途
泛型方法
在 java 中,泛型方法可以使用在成员方法、构造方法和静态方法中。语法如下:
public <申明泛型的类型> 类型参数 fun();如 public <T> T fun(T t)
;这里的 T 表示一个泛型类型,而 表示我们定义了一个类型为 T 的类型,这样的 T 类型就可以直接使用了,且 需要放在方法的返回值类型之前。T 即在申明的时候是不知道具体的类型的,只有的使用的时候才能明确其类型,T 不是一个类,但是可以当作是一种类型来使用。
泛型类
public class GenericClazz<T>{
//这就是一个最基本的泛型类的样子
}
1.4 小结
泛型是计算机程序中一种重要的思维方式,它将数据结构和算法与数据类型相分离,使得同一套数据结构和算法能够应用于各种数据类型,而且可以保证类型安全,提高可读性。
2. 常用通配符
Pair<String, ? extends Number> p = new Pair<>("name",123);
System.out.println(p.getKey()+p.getValue());
常用的通配符为: T,E,K,V,?
- ? 表示不确定的 java 类型
- T (type) 表示具体的一个 java 类型
- K V (key value) 分别代表 java 键值中的 Key Value
- E (element) 代表 Element
常用的通配符的三种形式
- <?> 无限定的通配符。是让泛型能够接受**未知类型**的数据
- < ? extends E>有上限的通配符。能接受指定类及其子类类型的数据,E就是该泛型的上边界
- <? super E>有**下限**的通配符。能接受**指定类及其父类类型**的数据,E就是该泛型的下边界
2.1 理解通配符
- 单独的
?
表示无限定通配符 -
? extends Number
表示有限定通配符,表示插入Number的某个子类
不过,通配符形式更为简洁。虽然通配符形式更为简洁,但上面两种通配符都有一个重要的限制:只能读,不能写。
通配符的优点
- 它们的目的都是为了使方法接口更为灵活,可以接受更为广泛的类型。
- <? >和<? extends E>用于灵活读取,使得方法可以读取E或E的任意子类型的容器对象,它们可以用类型参数的形式替代,但通配符形式更为简洁。
- <? super E>用于灵活写入或比较,使得对象可以写入父类型的容器,使得父类型的比较方法可以应用于子类对象,它不能被类型参数形式替代。
2.2 总结
- 通配符形式都可以用类型参数的形式来替代,通配符能做的,用类型参数都能做。
- 通配符形式可以减少类型参数,形式上往往更为简单,可读性也更好,所以,能用通配符的就用通配符。
- 如果类型参数之间有依赖关系,或者返回值依赖类型参数,或者需要写操作,则只能用类型参数。
- 通配符形式和类型参数往往配合使用,比如,上面的copy方法,定义必要的类型参数,使用通配符表达依赖,并接受更广泛的数据类型。