泛型
(把类型明确的工作推迟到创建对象或调用方式的时候才去明确的特殊类型,只要编译期没有警告,运行期就不会出现ClassCastException异常)
1.定义
泛型提供了编译时类型安全检测机制,允许在编译时检测到非法的类型。
本质是参数化类型
- 把类型当作是参数一样传递
- <数据类型>只能是引用类型
ArrayList E称为类型参数 整个称为ArrayList泛型类型
ArrayList Integer称为实际类型参数 整个称为参数化的类型
有了泛型后可以使用增强for循环遍历集合。
ArrayList<String> list = new ArrayList<String>();
list.add("hello");
list.add("world");
list.add("java");
for(String s:list){
System.out.println(s);
}
一、泛型类
把泛型定义在类上,用户使用该类的时候再明确类型
二、泛型方法(泛型是先定义后使用)
// 定义泛型方法, new一个对象调用show方法,传什么类型返回什么类型
public <T> void show(T t) {
System.out.println(t);
}
三、泛型类派生出的子类
泛型类就是拥有泛型特性的类,也拥有继承关系。
实现类要是重写父类的方法,返回类型要和父类一致
类上声明的泛型只对非静态成员有效
- 子类明确泛型类的类型参数变量
// 把泛型定义在接口上。实现泛型接口的类。
public interface Inter<T> {
public abstract void show(T t);
}
// 子类明确泛型类的类型参数变量
public class InterImpl implements Inter<String>{
@Override
public void show(String s) {
System.out.println(s);
}
public static void main(String[] args) {
InterImpl inter = new InterImpl();
inter.show("hello");
}
}
- 子类不明确泛型类的类型参数变量
// 子类不明确泛型类的类型参数变量,子类也需要定义成泛型类型
public class InterImplOne<T> implements Inter<T> {
@Override
public void show(T t) {
System.out.println(t);
}
public static void main(String[] args) {
InterImplOne<String> stringInterImplOne = new InterImplOne<>();
stringInterImplOne.show("word");
}
}
四、类型通配符
eg: 方法接收一个集合参数,遍历打印。
// 报错写法:编译警告,没有确定集合类型
public class TongPeiFu {
public void test(List list){
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
在List后添加?
泛型里List和List无关。所以使用到通配符?
public class TongPeiFu {
public void test(List<?> list){
for (int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
使用通配符?时,只能调对象与类型无关的方法。
五、通配符上下限
-
通配符上限
当我想接收一个list集合,只能操作数字类型的元素(Integer,Double,Byte,Float等)
List<? extends Number> 表示List集合装载的元素只能时Number的子类或自身 -
通配符下限
<? super Type> 表示传递进来的只能时Type或者Type的父类 -
PECS(Producer Extends Consumer Super)原则
如果要从集合中读取类型T的数据,并且不能写入,可以使用 ? extends 通配符;(Producer Extends)
如果要从集合中写入类型T的数据,并且不需要读取,可以使用 ? super 通配符;(Consumer Super)
如果既要存又要取,那么就不要使用任何通配符。
如果参数之间的类型有依赖关系,或者返回值时与参数之间有依赖关系的,使用泛型方法。
如果没有依赖关系的,使用通配符,灵活一些。
六、泛型擦除
泛型时提供给javac编译器使用的,用于限定集合的输入类型,让编译器在源代码级别上,避免向集合中插入非法数据。但编译器编译完带有泛型的java程序后,生成的class文件中不再带有泛型信息,以此使程序运行效率不受影响,这个过程称为擦除。
当把带有泛型特性的集合赋值给老版本的集合时,会把泛型进行擦除,(jdk5以前没有泛型)