概述
Java 泛型(generics)是 JDK 5 中引入的一个新特性, 泛型提供了编译时类型安全检测机制,该机制允许程序员在编译时检测到非法的类型。泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
主要思想
把算法和数据结构完全分离开,使得一次定义的算法能够提供多种数据结构的使用,从而实现高度可重用开发。
优点
泛型的出现使得程序的类型检测更加的安全,同时提供了一次编写,重复利用的便利,在能够使用泛型方法的时候,尽量使用。
泛型类
泛型类,又称为参数化类型,是含有一个或者多个类型参数的类或者接口。泛型类定义实际的类或者接口时,只需要用具体的类型替换类型变量即可实例化泛型类型。
public class Abc<T>{ //<T>为类型化参数列表,此处为单个类型参数
... //泛型定义的体
}
public class Gen<KeyType,ValueType>{ //多个类型参数之间用逗号隔开
...
}
具体例子:
public class OverClass<T> { //定义泛型
private T over;
public T getOver() {
return over;
}
public void setOver(T over) {
this.over=over;
}
public static void main(String[] args) {
OverClass<Boolean> exp1=new OverClass<Boolean>();
exp1.setOver(true);
OverClass<Float> exp2=new OverClass<Float>(); //不能使用一般的数据类型,即便使用,也要用该数据类型对应的包装类
exp2.setOver(1.2f);
Boolean b=exp1.getOver(); //避免了一般类型发生向下转型时出现的问题,提高程序安全
Float f=exp2.getOver();
System.out.println(b);
System.out.println(f);
}
}
需要注意:泛型类或泛型方法的类型实参只能是类或者接口,不可以使用基本数据类型作为实参,但是可以用基本数据类型对应的包装类来作为实参。
Java中的集合框架都已经被泛型化了,所以在使用的时候都可以直接对其进行实例化。
集合类 | 泛型定义 |
---|---|
ArrayList | ArrayList< E > |
HashMap | HashMap< K,V > |
HashSet | HashSet< E > |
Vector | Vector< E > |
运用实例
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class AnyClass {
public static void main(String[] args) {
ArrayList<Integer> a=new ArrayList<Integer>();
for (int i = 0; i < 5; i++) {
a.add(i); //为ArrayList添加元素
}
Iterator<Integer> it=a.iterator(); //通过迭代器进行数据遍历
while(it.hasNext()){ //判断是否还存在元素可迭代,是返回true
Integer temp=(Integer)it.next(); //获取迭代的下一个元素,这里要对其进行强转,因为next返回的Object类型
System.out.println(temp);
}
//定义泛型时,申明多个类型
Map<Integer,String> m=new HashMap<Integer, String>();
for (int i = 0; i < 5; i++) {
m.put(i, "成员"+i);
}
Set<Integer> set=m.keySet();
Iterator<Integer> its=set.iterator();
while(its.hasNext()) {
Integer k=(Integer)its.next();
String value=m.get(k);
System.out.println("key值 "+k+" 对应的values:"+value);
}
}
}
泛型方法
泛型方法
含有一个或者多个独立的参数类型的方法称为泛型方法,泛型方法也称参数化方法。泛型方法可以是普通类的方法也可以是泛型类的方法,是否拥有泛型方法与其所在的类是否是泛型类无关。
class Abc{
public static <T> void listabc(LinkedList<T> linlist){方法体}
}
方法调用举例
String[] name={"Wang","Shaochuan"};
String str=Abc.<String>getMiddle(name);
//Abc是类名,getMiddle()是泛型方法
//<String>在实际调用的时候可以省略,编译器能够自主判断所调用方法的类型。
类型参数限定
有时在泛型定义中需要对类实例的类型实参做些约束,以保证它们是对特定类的扩展,对特定接口的实现,或者两者都有。这种约束称为类型参数限定。
<T extends BoundingType>
T的实际类型必须是BoundingType类型的下层类型或者下层接口类型,T和BoundingType必须是类或者接口。
多个限定如下:
<T extends Abc&Bcd>
对T的多个限定,限定之间使用&分隔开,对类型参数的第一个限定可以是类或者借口,但是之后的限定只能是接口(Java的继承机制),即类作为限定时,必须是作为第一个限定。无限定时,将用Object作为隐含的限定,即如下。
public class a<T>{
...
}
//上下两种形式等价
public class a<T extends Object>{
...
}
泛型类型限制除了可以向下限制之外,还可以向上限制,只要在定义时使用super关键字即可。
A<T super List> a=null; //对象a只接受List接口或上层父类类型
通配符
通配符就是符号“?”。除了可以给泛型提供具体的类型作为实参外,还可以把实参写为通配符“?”,通配符类型可以代表任何类或者接口。
A<? extends List> a=null;
a=new A<ArrayList>();
a=new A<LinkedList>()
下面通过一个具体的例子来解释有无通配符的区别
import java.util.ArrayList;
import java.util.List;
public class LimitClass<T extends List> {
public static void main(String[] args) {
LimitClass<ArrayList> l1=new LimitClass<ArrayList>();
//LimitClass<HashMap> l3=new LimitClass<HashMap>();
List<String> l2=new ArrayList<String>();
l2.add("成员");
List<?> l3=l2;
List l4=l2;
l2.set(0, "L2成员改变"); //将0号索引位置的对象修改为“L2成员改变”
l4.set(0, "L4成员改变");
//l3.set(0, "L3成员改变");
System.out.println(l2.get(0)); //获取指定索引位置对象的值
System.out.println(l3.get(0));
System.out.println(l4.get(0));
}
}
上述例子中,l3.set(0, “L3成员改变”);将会报错,原因就在于使用通配符申明的实例化对象不能对其加入新的信息,只能获取和删除。这也是 List< ? > l3=l2语句和 List l3=l2之间的区别。