java学习笔记(8) - 泛型介绍(1)
泛型(1) - 泛型类 , 泛型接口
什么是泛型?为什么需要泛型?
- 泛型,即“参数化类型”。一提到参数,最熟悉的就是定义方法时有形参列表,普通方法的形参列表中,每个形参的数据类型是确定的,而变量是一个参数。在调用普通方法时需要传入对应形参数据类型的变量(实参),若传入的实参与形参定义的数据类型不匹配,则会报错。
那
参数化类型
是什么?以方法的定义为例,在方法定义时,将方法签名中的形参的数据类型
也设置为参数(也可称之为类型参数),在调用该方法时再从外部传入一个具体的数据类型和变量。
泛型使用场景
在 ArrayList
集合中,可以放入所有类型的对象,假设现在需要一个只存储了 String
类型对象的 ArrayList
集合。
@ Test |
- 上面代码没有任何问题,在遍历
ArrayList
集合时,只需将Object
对象进行向下转型成String
类型即可得到String
类型对象。
但如果在添加 String
对象时,不小心添加了一个 Integer
对象,会发生什么?看下面代码:
@ Test |
上述代码在编译时没有报错,但在运行时却抛出了一个
ClassCastException 异常
,其原因是 Integer 对象不能强转为 String 类型。
- 那如何可以避免上述异常的出现?即我们希望当我们向集合中添加了不符合类型要求的对象时,编译器能直接给我们报错,而不是在程序运行后才产生异常。这个时候便可以使用
泛型
了。
@ Test |
< String >
是一个泛型,其限制了ArrayList
集合中存放对象的数据类型只能是String
,当添加一个非String
对象时,编译器会直接报错。这样,我们便解决了上面产生的ClassCastException
异常的问题(这样体现了泛型的类型安全检测机制)。
泛型概述小结
与使用
Object
对象代替一切引用数据类型对象这样简单粗暴方式相比,泛型使得数据类型的类别可以像参数一样由外部传递进来。它提供了一种扩展能力,更符合面向对象开发的软件编程宗旨。当具体的数据类型确定后,泛型又提供了一种
类型安全检测机制
,只有数据类型相匹配的变量才能正常的赋值,否则编译器就不通过。所以说,泛型一定程度上提高了软件的安全性,防止出现低级的失误。泛型提高了程序代码的可读性。在定义泛型阶段(类、接口、方法)或者对象实例化阶段,由于
< 类型参数 >
需要在代码中显式地编写,所以程序员能够快速猜测出代码所要操作的数据类型,提高了代码可读性。
泛型有三种使用方式,分别为:泛型类、泛型接口、泛型方法,下面将正式介绍泛型的相关知识。
泛型类
- 类型参数用于类的定义中,则该类被称为泛型类。通过泛型可以完成对一组类的操作对外开放相同的接口。最典型的就是各种容器类,如:
List
、Set
、Map
等。
基本语法如下:
class 类名称 <泛型标识> { |
- 尖括号 <> 中的 泛型标识被称作是
类型参数
,用于指代任何数据类型。- 泛型标识是任意设置的(如果你想可以设置为 Hello都行),Java 常见的泛型标识以及其代表含义如下:
T :代表一般的任何类。
E :代表 Element 元素的意思,或者 Exception 异常的意思。
K :代表 Key 的意思。
V :代表 Value 的意思,通常与 K 一起配合使用。
S :代表 Subtype 的意思,文章后面部分会讲解示意。
举例如下:
public class Generic<T> { |
- 一般来讲,在泛型类中,静态方法和静态变量不可以使用泛型类所声明的类型参数
public class Test<T> { |
泛型类的使用
- 在创建泛型类的对象时,必须指定类型参数 T 的具体数据类型,即尖括号 <> 中传入的什么数据类型,T 便会被替换成对应的类型。如果 <> 中什么都不传入,则默认是 < Object >。
// 这里我定义一个 Generic 泛型类 |
- 在传入
String
后的原泛型类的拓展:
public class Generic { |
- 可以发现,泛型类中的
类型参数 T
被 <> 中的 String 类型全部替换了。- 使用泛型的上述特性便可以在集合中限制添加对象的数据类型,若集合中添加的对象与指定的泛型数据类型不一致,则编译器会直接报错,这也是泛型的类型安全检测机制的实现原理。
泛型接口
泛型接口和泛型类的定义差不多,基本语法如下:
public interface 接口名<类型参数> { |
重要!泛型接口中的类型参数,在该接口被继承或者被实现时确定。解释如下:
- 1. 定义一个泛型接口
interface IUsb<U, R> { |
2. 定义一个接口 IA 继承了 泛型接口 IUsb,在 接口 IA 定义时必须确定泛型接口 IUsb 中的类型参数。
// 在继承泛型接口时,必须确定泛型接口的类型参数 |
3. 定义一个类 BB 实现了 泛型接口 IUsb,在 类 BB 定义时需要确定泛型接口 IUsb 中的类型参数。
// 实现接口时,需要指定泛型接口的类型参数 |
4. 定义一个类 CC 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,则默认为 Object。
// 实现泛型接口时没有确定类型参数,则默认为 Object |
5. 定义一个类 DD 实现了 泛型接口 IUsb 时,若是没有确定泛型接口 IUsb 中的类型参数,也可以将 DD 类也定义为泛型类,其声明的类型参数必须要和接口 IUsb 中的类型参数相同。
// DD 类定义为 泛型类,则不需要确定 接口的类型参数 |