一.概述
1、泛型就是将类型由原来的具体的类型参数化,类似于方法中的变量参数,此时类型也定义成参数形式(可以称之为类型形参),然后在使用/调用时传入具体的类型(类型实参)。
2、泛型的本质是为了参数化类型(在不创建新的类型的情况下,通过泛型指定的不同类型来控制形参具体限制的类型)。也就是说在泛型使用过程中,操作的数据类型被指定为一个参数。
二.特性
1、泛型只在编译阶段有效,不会进入到运行时阶段。
2、泛型类型在逻辑上看以看成是多个不同的类型,实际上是相同的基本类型。
3、泛型的类型参数(实参)只能是类类型,不能是基本类型。
4、静态方法无法访问类上定义的泛型;如果静态方法操作的引用数据类型不确定的时候,必须要将泛型定义在方法上
5、类变量(静态变量)无法访问类上定义的泛型。
List<String> stringList = new ArrayList<>();
List<Integer> integerList = new ArrayList<>();
Class classString = stringList.getClass();
Class classInteger = integerList.getClass();
classInteger.equals(classString); // 返回true,两者类型相同
public class StaticGenerator<T> {
// 此时编译器会提示错误信息
public static void show(T t){}
// 这个T跟类上的T不一样
public static <T> void show(T t){ }
}
三.泛型类
E:元素(Element),多用于java集合框架
T:类型(Type)
N:数字(Number)
K:关键字(Key)
V:值(Value)
public class Generic<T>{
// key这个成员变量的类型为T, T的类型由外部指定
private T key;
//泛型构造方法形参key的类型也为T,T的类型由外部指定
public Generic(T key) { this.key = key; }
//泛型方法getKey的返回值类型为T,T的类型由外部指定
public T getKey(){ return key; }
}
/**
* 定义的泛型类,就一定要传入泛型类型实参么?并不是这样,
* 在使用泛型的时候如果传入泛型实参,则会根据传入的泛型实参做相应的限制。
* 如果不传入泛型类型实参的话,在泛型类中使用泛型的方法或成员变量定义的类型可以为任何的类型。
**/
Generic generic = new Generic("111111");
Generic<Integer> genericInteger = new Generic<Integer>(123456);
四.泛型接口
// 定义一个泛型接口
public interface Generator<T> {
public T next();
}
// 未传入泛型实参时,与泛型类的定义相同,在声明类的时候,需将泛型的声明也一起加到类中
class FruitGenerator<T> implements Generator<T> {}
/**
* 在实现类实现泛型接口时,如已将泛型类型传入实参类型,则所有使用泛型的地方都要替换成传入的实参类型
**/
public class FruitGenerator implements Generator<String> {
@Override
public String next() { }
}
五.泛型方法
public class Generator<E> {
// 这只是类中一个普通的成员方法,只不过他的返回值是在声明泛型类已经声明过的泛型
public E showA(E name ) { }
// 这也不是一个泛型方法,这就是一个普通的方法,只是使用了Generic<Number>这个泛型类做形参而已。
public void showB(Generic<Number> obj) { }
// 这也不是一个泛型方法,这也是一个普通的方法,只不过使用了泛型通配符?
public void showC(Generic<?> obj){ }
/**
* 这才是一个真正的泛型方法。
* 首先在public与返回值之间的<T, K>必不可少,这表明这是一个泛型方法,并且声明了一个泛型<T, K>
*/
public <T, K> T showKeyName(Generic<K> container)
}
六.泛型通配符
1、类型通配符一般是使用?代替具体的类型实参
2、此处的?和Number、String、Integer一样都是一种实际的类型,可以把?看成所有类型的父类。是一种真实的类型。
3、泛型通配符?只能用于函数参数或者函数内部的使用泛型类中,其他场景不能使用。
// 泛型通配符用于函数内部使用泛型类实参无边界
public void showKeyValue1(){
List<?> list = new ArrayList<>();
}
// 泛型通配符用于函数内部使用泛型类实参有上边界
public void showKeyValue2(){
List<? extends Number> list = new ArrayList<>();
}
// 泛型通配符用于函数参数使用泛型类实参无边界
public void showKeyValue3(List<?> list){
}
// 泛型通配符用于函数参数使用泛型类实参有上边界
public void showKeyValue4(List<? extends Number> list){
}
七.泛型上下边界
// 泛型类的定义使用上边界
public class Generic<T extends Number> { }
// 泛型方法的定义使用上边界
public <T extends Number> T showKeyName(Generic<T> container) {}
网友评论