泛型的本质就是参数化类型(类型参数),什么是参数化类型呢?
就是所操作的数据类型被指定为一个参数,这种参数可以用在类、接口和方法的创建中,分别称为泛型类、泛型接口、泛型方法。
注:泛型类型参数:编译器进行类型安全检测,擦除到Object类型(没有进行参数的约束)
泛型类:
一般用于封装非特定数据类型的操作,操作执行的大体相同,与所存储的数据类型无关。
泛型类的声明与一般类的声明语法一致,但需要在声明的泛型接口名称后使用”<>”,制定类型参数;
public class TypeTest<T> {
private T[] arr;
private int size;
private T t;
public TypeTest(){
// arr = new T[10]; //无法直接new泛型的数组
arr = (T[])new Object[10]; //解决方法,new Object 类型的数组,然后强转成 T 类型
// t = new T(); //无法直接new泛型对象
t = (T)new Object();
size = 0;
}
public void add(T value){
arr[size++] = value;
}
}
public class TypeTestTestDemo {
public static void main(String[] args){
TypeTest<String> typeTest = new TypeTest<>();
typeTest.add("Hello");
typeTest.add("world");
}
}
泛型错误:
- 不能直接new泛型数组 (解决方法:1. (T[])new Object[10] 2.反射)
- 不能实例化泛型对象,因为不知道类型
- 泛型参数类型不能是基本数据类型,即只能是引用数据类型(泛型参数不指定力体类型时,默认为Object类)
- 泛型参数不遵循向上造型
- 在 static 方法中,是不能用泛型类型参数的。因为 static 方法是不依赖对象存在的,所以无法推知static 泛型参数类型
泛型接口:
在泛型类的设计中,通常把泛型类共同要实现的方法的签名封装为泛型接口,然后在实现这些接口的泛型类中实现这些方法。泛型接口的声明语法和一般接口的声明语法一致,但需要在声明泛型的接口名称后加“<>”指定一个或者多个类型参数。
interface MyArrayList<E>{
void add(E e);
}
interface MyList<K,V>{
void put(K key,V value); //类型参数可以是多个
}
class MyArray implements MyArrayList<String>{
@Override
public void add(String s) {
}
}
泛型方法:
再此之前看到的泛型都是应用在整个类上,但同样可以包含参数化方法,而这个方法所在的类可以是泛型类也可以不是泛型类。也就是说,是否拥有泛型方法与其所处的类是否是泛型类毫无关系。方法中,通过指定类型参数,可以声明泛型方法,从而提高其可复用性。
泛型方法的参数化类型列表放在方法类符的后面返回值之前。
public static <T> void swap(T a,T b){
T temp = a;
a = b;
b = temp;
}
public static void main(String[] args){
Integer a = 10;
String b = “Hello”;
swap(a,b); // T将会擦除到Object,即T是Object类
}
使用泛型方法需要注意的点:
- 如果泛型方法的泛型参数与类型的泛型参数相同,编译器生成警告,因为方法的泛型参数隐藏了外部类型的泛型参数
class MyGenerics<T>{
public <T> void fun(T t){
}
}
- 直接可以通过”方法名()”的形式进行泛型方法的调用,编译器根据传入的方法实参推衍出类型形参。
- 使用约束对泛型类型参数启到约束的作用。
public static <T extends Comparable<T>> void swap(T[] a,int i,innt j){
T temp;
if(a[i].compareTo(a[j]) > 0){ //不是if(a[i] > a[j])
temp = a[i];
a[i] = a[j];
a[j] = temp;
}
}
泛型参数的约束(类型擦除):
默认情况下,没有约束条件的泛型类型参数(Sample)T 称为未绑定类型参数,当创建未绑定类型参数的泛型类实例时,可以给参数类型指定任意类型。想要让泛型参数支持特定类型时,可以使用关键字 extends或者 super 关键字对泛型参数进行约束。
1.extends 主要限定泛型参数的上界(常见的使用如下):
<T extends 基类> //T 只能是基类或者基类的派生类
<T extends 基接口> //T 只能是实现基接口的派生类
2.通配符的约束
<? extends 基类> //其中表明?未知类型限定为指定类或者指定类的派生类。指定上界。
<? super 派生类> //其中?未知类型限定为指定类或者指定类的基类。指定下界。
泛型问题:
- java编译器先检查泛型的类型,然后再进行类型的擦除。
- 泛型在引用变量之间传值过程中的应用
- 泛型中参数化类型不考虑继承关系
- 不能定义自定义泛型数组
- 泛型类型变量不能是基本数据类型
- 泛型在静态方法和静态类中的问题:
泛型类中的静态方法和静态变量不可以使用泛型类所声明的泛型类型参数(可以定义成泛型方法)