泛型
定义
泛型:就是适用于许多许多类型。
为什么要有泛型?
1.当我们要写数字的时候,我们给它int类型;当我们要写姓名的时候,我们给它String类型;又或者是我们自己定义的student类等等。
2.上面的给类型操作往往会造成一种无形的束缚,为了摆脱这种束缚,数据结构中就存在了可以应用于多种类型的代码 。这种代码就是泛型——对类型实现了参数化。
具体例子(数组)
我们以前学过的数组,只能存放指定类型的元素,例如:int[] array = new int[10]; String[] strs = new String[10];
我们知道所有类的父类, 默认为Object,那我们可以尝试创建一个Object类的数组。
特点
-
任何类型数据都可以存放
-
1号下标本身就是字符串,但是确编译报错。必须进行强制类型转换
虽然在这种情况下,当前数组任何数据都可以存放,但是,更多情况下,我们还是希望他只能够持有一种数据类型。而不是同时持有这么多类型。所以,泛型的主要目的:就是指定当前的容器,要持有什么类型的对象。让编译器去做检查。 此时,就需要把类型,作为参数传递。需要什么类型,就传入什么类型。
泛型语法
把类型,作为参数传递。需要什么类型,就传入什么类型。
第一种
class 泛型类名称<类型形参列表> {
// 这里可以使用类型参数
}
例子:
class ClassName<T1, T2, ..., Tn> {
}
第二种
class 泛型类名称<类型形参列表> extends 继承类/* 这里可以使用类型参数 */ {
// 这里可以使用类型参数
}
例子:
class ClassName<T1, T2, ..., Tn> extends ParentClass<T1> {
// 可以只使用部分类型参数
}
- 类名后的 < T > 代表占位符,表示当前类是一个泛型类 ,可以写多个。
- E 表示 Element (元素)
- K 表示 Key (关键字)
- V 表示 Value (值)
- N 表示 Number (数字)
- T 表示 Type (类型)
此时代码变为:
- 注释1:不能new泛型类型的数组 T[] ts = new T[5]; 是不对的
- 注释2:实例化中写的这个""指定当前类型,最右边<>编译器会在存放元素的时候帮助我们进行类型检查。
泛型类的使用
泛型类<类型实参> 变量名 = new 泛型类<类型实参>(构造方法实参);
- MyArray list = new MyArray()
- 泛型只能接受类,所有的基本数据类型必须使用包装类!
裸泛型(了解)
裸类型是一个泛型类但没有带着类型实参
注意: 我们不要自己去使用裸类型,裸类型是为了兼容老版本的 API 保留的机制
泛型是如何编译的(擦除机制)面试题
泛型是一种在编译时期的机制,我们称之为擦除机制
通过命令:javap -c 查看字节码文件,所有的T都是Object
在编译的过程当中,将所有的T替换为Object这种机制,我们称为:擦除机制。
那为什么,T[] ts = new T[5]; 是不对的,编译的时候,替换为Object,不是相当于:Object[] ts = new Object[5]吗?
因为编译器认为不安全,为什么不安全?请看下面这张图
泛型的上界
在定义泛型类时,有时需要对传入的类型变量做一定的约束,可以通过类型边界来约束。
语法
语法进阶版
当我们要实现一个求数组中最大值的泛型类
泛型方法
泛型当中的方法
语法
实例
实现一个求数组中最大值的泛型类
//泛型方法,对方法中的类型形参列表进行修改
//方法限定符 <类型形参列表> 返回值类型 方法名称(形参列表) { ... }
class Alg2 {
public <T extends Comparable<T>> T findMaxVal(T[] array) {
T max = array[0];
for (int i = 0; i < array.length; i++) {
if (array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
public static void main(String[] args) {
Alg2 alg2 = new Alg2();//实例化
Integer[] array = {1,2,3,7,8,6};
alg2.<Integer>findMaxVal(array);//<>可以不写,能够通过array的类型推导出来为Integer
alg2.findMaxVal(array);
}
不实例化的写法
/对方法加入static的时候,就不需要实例化了
class Alg3 {
public static <T extends Comparable<T>> T findMaxVal(T[] array) {
T max = array[0];
for (int i = 1; i < array.length; i++) {
if(array[i].compareTo(max) > 0) {
max = array[i];
}
}
return max;
}
}
public class Test {
//不用实例化的泛型方法: Alg3
public static void main(String[] args) {
//可以不实例化
Integer[] array = {1,2,3,7,8,6};
System.out.println(Alg3.<Integer>findMaxVal(array));
System.out.println(Alg3.findMaxVal(array));
}
Alg-Alg2-Alg3明显的区别
泛型总结
1.泛型是将数据类型参数化,进行传递。
2.使用 < T > 表示当前类是一个泛型类。
3.泛型目前为止的优点:数据类型参数化,编译时自动进行类型检查和转换。
4.裸泛型不建议使用,是为了兼容老版本。
5.擦除机制是把**所有的T替换为Object。
6.泛型只有上界,没有下界。
7.泛型方法简单的运用(Comparable)。