概述
- 本质是参数化类型
- 通过泛型指定的类型范围来 限制参数的类型
在编译时可检测非法类型
Java中的泛型只在编译阶段有效
过程:
1、查找用来替换类型参数的具体类(一般为 Object),如果指定了类型参数的上界,则以该上界做为替换时的具体类;
2、把代码中的类型参数都替换为具体的类。
泛型使用
三种使用方式:泛型类、泛型接口、泛型方法
泛型类
// 此处T可以随便写为任意标识,常见的如T、E、K、V等形式的参数常用于表示泛型
// 在实例化泛型类时,必须指定T的具体类型
public class Generic<T>{
// key这个成员变量的类型为T,T的类型由外部指定
private T key;
public Generic(T key) { // 泛型构造方法形参key的类型也为T,T的类型由外部指定
this.key = key;
}
public T getKey(){ // 泛型方法getKey的返回值类型为T,T的类型由外部指定
return key;
}
}
定义的泛型类,
如果传入泛型实参,则会根据传入的泛型实参做相应的类型限制;
如果不传泛型实参,在泛型类中使用的泛型类型可以是任何类型。
注意:
- 泛型的类型参数只能是类类型,不能是简单类型
- 不能对确切的泛型类型使用 instanceof 操作,编译时会报错
泛型接口
//定义一个泛型接口
public interface Generator<T> {
public T next();
}
实现泛型接口类:
不传泛型实参
复制代码
/**
* 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
* 即:class FruitGenerator<T> implements Generator<T>{
* 如果不声明泛型,如:class FruitGenerator implements Generator<T>,编译器会报错:"Unknown class"
*/
class FruitGenerator<T> implements Generator<T>{
@Override
public T next() {
return null;
}
}
传入泛型实参
/**
* 如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
*/
public class FruitGenerator implements Generator<String> {
private String[] fruits = new String[]{"Apple", "Banana", "Pear"};
@Override
public String next() {
Random rand = new Random();
return fruits[rand.nextInt(3)];
}
}
泛型方法
泛型类,在实例化类的时候指明泛型的具体类型;
泛型方法,在调用方法的时候指明泛型的具体类型。泛型方法必须有泛型的声明 ```java /**
- 这才是一个真正的泛型方法。
- 首先在public与返回值之间的
必不可少,这表明这是一个泛型方法,并且声明了一个泛型T - 这个T可以出现在这个泛型方法的任意位置.
- 泛型的数量也可以为任意多个
*/
public
K showKeyName(Generic container){ … }
// 这不是一个泛型方法,这就是一个普通的方法,只是使用了Generic
// 这也不是一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符? // ?是一种类型实参,可以看做为Number等所有类的父类 public void showKeyValue2(Generic<?> obj){ Log.d(“泛型测试”,”key value is “ + obj.getKey()); }
- 泛型类中 泛型方法声明的泛型 和 泛型类声明的泛型 无关
```java
class GenerateTest<T> {
public void show_1(T t){
System.out.println(t.toString());
}
//在泛型类中声明了一个泛型方法,使用泛型E,这种泛型E可以为任意类型。可以类型与T相同,也可以不同。
//由于泛型方法在声明的时候会声明泛型<E>,因此即使在泛型类中并未声明泛型,编译器也能够正确识别泛型方法中识别的泛型。
public <E> void show_3(E t){
System.out.println(t.toString());
}
//在泛型类中声明了一个泛型方法,使用泛型T,注意这个T是一种全新的类型,可以与泛型类中声明的T不是同一种类型。
public <T> void show_2(T t){
System.out.println(t.toString());
}
}
泛型方法中可以使用可变参数
public <T> void printMsg( T... args){ for(T t : args){ Log.d("泛型测试","t is " + t); } }
静态方法的泛型声明只能在方法上,不能使用泛型类定义的泛型
类型通配符
? 表示所有具体的参数类型,例如 List<?> 在逻辑上 是所有 List<具体类型实参>的父类
泛型的上下边界定义
可以为泛型实参进行上下边界的设置
- 泛型的上下边界设置,必须和声明一起
- 上限的限定 <? extends T> 必须是 T 的子类
- 下限的限定 <? super T> 必须是 T 的父类 ```java // 普通方法限制 传入类型必须是 Number 的子类 public void showKeyValue1(Generic<? extends Number> obj){ Log.d(“泛型测试”,”key value is “ + obj.getKey()); }
// 泛型方法限制 上下边界的设置是在声明部分
public
// 泛型类
public class Generic