泛型
为什么需要泛型
那么为什么要有泛型呢,直接 Object 不是也可以存储数据吗?
- 解决元素存储的安全性问题,确定数据类型。
- 解决获取数据元素时,需要类型强制转换的问题。
Java 泛型可以保证如果程序在编译时没有发出警告,运行时就不会产生 ClassCastException 异常。同时,代码更加简洁、健壮。
自定义泛型结构
自定义泛型类 泛型接口
泛型接口与泛型类类似,这里以泛型类为例子。
父类有泛型,子类可以选择保留泛型也可以选择指定泛型类型:
- 子类不保留父类的泛型:
- 擦除,相当于泛型类型为 Object。
- 指定具体类型,如指定为 Integer。
- 子类保留父类的泛型:
- 全部保留。
- 部分保留,不保留的部分需要指定。
1 | class Father<T1, T2> { |
自定义泛型方法
方法也可以被泛型化,不管此时定义在其中的类是不是泛型类。在泛型方法中可以定义泛型参数,此时参数的类型就是传入数据的类型。泛型方法的格式:
1 | [方法权限] <泛型> 返回类型 方法名([泛型标识 参数名称]) [抛出的异常]; |
通配符
使用类型通配符:?,比如:List<?>
是 List<String>
、List<Object>
等各种泛型 List 的父类。
注意:
- 将任意元素加入到其中不是类型安全的:
- 唯一的例外的是 null,它是所有类型的成员。
1 | Collection<?> c = new ArrayList<String>(); |
- 可以调用 get() 方法并使用其返回值:返回值是一个未知类型,但总是一个 Object 类型。
有限制的通配符
- 指定通配符上限
<? extends ClassName>
:只允许泛型为 className 以及 ClassName 的子类。 - 指定通配符下限
<? super ClassName>
:只允许泛型为 ClassName 以及 ClassName 的父类。 - 指定接口
<? extends InterfaceName>
:只允许泛型为实现 InterfaceName 接口的实现类。