泛型的含义
- 泛型是一种类型参数, 专门用来保存类型的
泛型的优点
- 集合若不指定泛型, 默认参数类型为Object, 存储的元素类型会自动提升到Object类型, 在获取元素时得到的也都是Object对象, 若要调用子类特有的方法需要向下转型, 这也给我们编程带来了一定的麻烦
- 而如果我们指定了泛型, 可以在编译时就对类型做判断, 避免不必要的类型转换操作, 精简代码, 也避免了类型转换导致的错误
//泛型没有指定类型,默认就是Object
ArrayList list = new ArrayList();
list.add("Hello");
list.add("World");
list.add(100);
list.add(false);
//集合中的数据就比较混乱,会给获取数据带来麻烦
for (Object obj : list) {
String str = (String) obj;
//当遍历到非String类型数据,就会报异常出错
System.out.println(str + "长度为:" + str.length());
}
注意事项
- 泛型在代码运行时会被擦除, 我们利用反射可以在代码运行过程中添加其他类型的数据到集合
自定义泛型类
使用时机
- 在类中属性不知道具体类型时, 就可以自定义泛型类, 当然对于类中的方法也可以使用类定义的泛型
定义格式
- 在类名的后面加上一对尖括号, 里面定义泛型, 一般使用一个大写英文字母表示, 如果有多个泛型使用逗号进行分隔
- public class 类名<泛型名>{ }
泛型的确定
- 在创建对象时, 确定泛型的数据类型
ArrayList<String> list = new ArrayList<>();
自定义泛型接口
使用时机
- 当定义接口时, 内部方法中的参数类型, 返回值类型不确定时, 就可以使用泛型替代了
定义格式
-
在接口名的后面加上一对尖括号, 里面定义泛型, 一般使用一个大写英文字母表示, 如果有多个泛型使用逗号进行分隔
-
public interface 接口名<泛型名>{ }
泛型的确定
- 在创建对象时, 确定泛型的数据类型
- 例: ArrayList list = new ArrayList<>();
泛型的确定
- 子类如果可以确定类型, 在实现接口的时候, 直接确定类型
public class CollectionImp implements Collection<String> {
public boolean add(String e){
}
}
- 子类如果确定不了类型, 那么它就变成了一个自定义泛型类
自定义泛型方法
定义格式
- 修饰符 <泛型名> 返回值类型 方法名(参数类别) { }
public interface Collection<E> extends Iterable<E> {
<T> T[] toArray(T[] a); //将集合变成数组
}
泛型的指定
- 调用含有泛型的方法时, 传入的数据的类型就是泛型的类型
泛型通配符
- 当我们对泛型的类型确定不了,而想要表达的可以是任意类型,可以使用泛型通配符给定。符号就是一个问号: ?表示任意类型,用来给泛型指定的一种通配值。如下:
public static void shuffle(List<?> list) { }
- 泛型通配符搭配集合使用一般在方法的参数中比较常见
- 在集合中泛型是不支持多态的,如果为了匹配任意类型,我们就会使用泛型通配符了。
- 方法中的参数是一个集合,集合如果携带了通配符集合的类型会提升为Object类型。集合不能进行添加和修改操作,可以删除和获取
受限泛型
- <? super 类型> // 泛型的下限 只能是某一类型或其父类型
- <? extends 类型> // 泛型的上限 只能是某一类型或其子类型