什么是泛型?
泛型主要是java SE 1.5的特性,泛型的本质就是参数化类型,所谓的参数化类型就是所操作的数据类型被指定为一个参数,这种参数可以在类,接口个方法的创建中用到,分别称为泛型类,泛型接口,泛型方法,泛型类与泛型方法具备可重用性,类型安全性和高效性,这是非泛型类和非泛型方法无法具备的。
泛型的意义
1,可以对类型进行自动检查(不是替换,仅仅进行类型安全检查!!)
2,自动对类型进行类型转换。
泛型的定义
泛型定义通过泛型参数来进行定义,泛型的类型参数包含在"<>"中,类型参数用java标识符表示,通常使用大写字母如T,E等。
泛型类
泛型类一般用于封装非特定数据类型的操作,操作的执行方式大体相同,与所存储的数据类型无关。泛型声明与一般类的声明语法一致,但要在生命的泛型接口名称后使用“<>”,制定类型参数。
设计泛型类使需注意
- 哪些类型需要通用化为泛型类型参数
- 对泛型类型参数应用什么约束
- 是否将泛型行为分解为子类和基类
- 是否实现一个或多个泛型接口
示例:
class Test<T>{
private T name;//定义泛型成员变量
//构造函数
public Test(T name){
this.name=name
}
public T getName(){
return name;
}
public void setName(T name){
this.name=name;
}
public void show(){
System.out.println("T的实际类型是"+name.getClass(),getName());//name.getClass().getName()用于获取实际类型的名称
}
特别注意!!!
- 不能直接new泛型数组
- 不能定义泛型对象的数组
- 不能产生泛型类型对象
- 在static方法中,不能用泛型类型参数,因为static方法不依赖对象存在,所以无法推知static泛型参数类型
- 泛型参数类型不能是基本数据类型引用数据类型
泛型接口
在泛型类的设计中,通常把泛型类型共同实现的方法的签名封装为泛型接口,然后在实现这些接口的泛型类中实现这些方法。
示例:
interface MyLink<E>{
void add(E e);
}
interface MyLink<K,V>{
void put(K k,V v);
}
泛型方法
在方法中,通过指定类型参数,可以声明泛型方法,从而提高其可复用性,泛型方法的参数化类型列表放在方法修饰符的后面,返回值的前面。
如:交换函数
public static <T> void swap(T[] arr,int i,int j){
T temp=a[i];
a[i] = a[j];
a[j] = temp;
}
使用泛型方法需注意!!
- 如果泛型方法的泛型参数与类型的泛型参数相同,编译器生成警告,因为方法的泛型参数隐藏了外部类型的泛型参数。
- 直接可以通过"方法名()"的形式进行泛型方法的调用。
- 使用约束对泛型类型参数起到约束作用
泛型参数的约束
默认情况下,没有约束条件的泛型类型参数(Sample)T称为未绑定类型参数,当创建未绑定类型参数的泛型实例时,可以给参数类型指定任意类型。想要让泛型参数支持特定类型时,可以用关键字extends或者super对泛型进行约束
extends注要限定泛型参数的上界(常见使用):
<T extends 基类>;//T 只能是基类或者基类的派生类
<T extends 基接口>;//T 只能是实现基接口的派生类
示例
//定义一个测试类类型参数T只能是实现接口Comparable的派生类
class Test<T extends Comparable<T>>{
private T[] arr;
public Test(){
arr=(T[])new Object[2];
}
}