一、泛型定义
泛型是一种未知的数据类型,当我们不知道使用什么数据类型的时候,可以使用泛型。泛型也可以看出是一个变量,用来接收数据类型。
以集合类ArrayList源码为例:
//类定义时,不知道集合中会存储什么类型的参数,所以类型使用泛型
//E:未知的数据类型
public class ArrayList<E> extends AbstractList<E>
implements List<E>, RandomAccess, Cloneable, java.io.Serializable
//成员方法get
public E get(int index) {}
//成员方法add
public boolen add(E e){}
二、泛型使用
以集合类ArrayList创建具体类型时为例:
//创建集合对象时指定String数据类型
Collection<String> collection = new ArrayList<>();
/**
* public boolean add(E e):把给定的对象添加到当前集合中。
*/
collection.add("Hello");
collection.add("World");
collection.add("!!!!!");
三、使用泛型的好处
不使用泛型在程序运行期可能会发生类型转换错误
public static void main(String[] args) {
ArrayList arrayList = new ArrayList<>();
//不使用时泛型时,集合中可以任意加入Object类型
arrayList.add("Hello");
arrayList.add(100000);
Iterator iterator= arrayList.iterator();
while(iterator.hasNext()){
Object object= iterator.next();
System.out.println(object);
//不使用泛型,在程序运行期进行Object类型强制转换时会发生类型转换错误
//Exception in thread "main" java.lang.ClassCastException:
// java.lang.Integer cannot be cast to java.lang.String
String string =(String)object;
System.out.println(string);
}
}
使用泛型在代码编译期就可以提示类型错误
public static void main(String[] args) {
//定义时指定String类型
ArrayList<String> arrayList = new ArrayList<>();
arrayList.add("Hello");
//在编译期时就发生错误
//arrayList.add(100000);
//迭代器根据集合对象的数据类型进行定义
Iterator<String> iterator= arrayList.iterator();
while(iterator.hasNext()){
//使用泛型,由于在定义时就指定了数据类型,不需要进行类型转换
String string = iterator.next();
System.out.println(string);
}
}
四、定义含有泛型的类
泛型类,是在实例化类的时候指明泛型的具体类型
以下代码为定义含有泛型的类MyGenericClass
/**
* @author zhuhuix
*/
public class MyGenericClass<E> {
private E name;
public E getName() {
return name;
}
public void setName(E name) {
this.name = name;
}
public static void main(String[] args) {
//创建MyGenericClass对象,泛型使用String
MyGenericClass<String> myGenericClass1 = new MyGenericClass<>();
myGenericClass1.setName("jack");
System.out.println(myGenericClass1.getName());
//创建MyGenericClass对象,泛型使用Integer
MyGenericClass<Integer> myGenericClass2 = new MyGenericClass<>();
myGenericClass2.setName(10000);
System.out.println(myGenericClass2.getName());
}
}
五、定义含有泛型的方法
泛型方法,是在调用方法的时候指明泛型的具体类型
以下代码为普通类为定义一个泛型的方法
/**
* @author zhuhuix
* 定义一个普通类,在普通类中定义泛型方法及调用
*/
public class MyGenericMethod {
//定义泛型的方法:在public 与void之间有一个泛型T,可以认为此方法为泛型方法
public <T> void myMethod(T t){
System.out.println(t);
}
public static void main(String[] args) {
MyGenericMethod myGenericMethod = new MyGenericMethod();
//调用泛型方法时指定泛型参数为String
myGenericMethod.myMethod("Hello");
//调用泛型方法时指定泛型参数为Integer
myGenericMethod.myMethod(10000);
}
}
五、定义含有泛型的接口
泛型接口与泛型类的定义及使用相同。
/**
* @param <T> 接口中的泛型
* @author zhuhuix
*/
public interface MyGenericInterface<T> {
void myGenericIntefaceMethod(T t);
}
//接口中使用泛型,则实现类也必须使用泛型
public class MyGenericInterfaceImpl<T> implements MyGenericInterface<T> {
@Override
public void myGenericIntefaceMethod(T t) {
System.out.println(t);
}
public static void main(String[] args) {
//创建MyGenericInterface对象,指定泛型为String
MyGenericInterface<String> myGenericInterface1= new MyGenericInterfaceImpl<>();
myGenericInterface1.myGenericIntefaceMethod("Hello World");
//创建MyGenericInterface对象,指定泛型为Integer
MyGenericInterface<Integer> myGenericInterface2= new MyGenericInterfaceImpl<>();
myGenericInterface2.myGenericIntefaceMethod(111111);
}
}
六、泛型的通配符
1、泛型通配符的常规用法
泛型的通配符用 ? 表示,代表任意的数据类型,不能创建对象使用,只能作为方法的参数使用。也就是说泛型通配符?只能出现在方法的参数中。
/**
* @author zhuhuix
*/
public class MyGenericMatch {
//该成员方法通过迭代器进行遍历ArrayList,
// 但传入的集合参数为不确定的数据类型,所以用泛型通配符进行定义
public static void printArray(ArrayList<?> arrayList){
Iterator<?> iterator = arrayList.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
public static void main(String[] args) {
ArrayList<String> arrayListString = new ArrayList<>();
arrayListString.add("Hello");
arrayListString.add("World");
arrayListString.add("!!!!!");
ArrayList<Integer> arrayListInteger = new ArrayList<>();
arrayListInteger.add(1);
arrayListInteger.add(2);
arrayListInteger.add(3);
//通配String类型
printArray(arrayListString);
//通配Integer类型
printArray(arrayListInteger);
}
}
2、泛型通配符的上限限定与下限限定
上限限定: ? extends E 代表使用的泛型只能是E类型的子类/本身
下限限定: ? super E 代表使用的泛型只能是E类型的父类/本身
也就是说通过上下限的限定,限定方法参数数据类型的范围。
/**
* @author zhuhuix
*/
public class MyGenericMatchLimit {
//泛型上限限定:泛型通配符?必须时Number类型或者Number类型的子类
public static void printCollection1(Collection<? extends Number> collection){
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
//泛型下限限定:泛型通配符?必须时Number类型或者Number类型的父类
public static void printCollection2(Collection<? super Number> collection){
Iterator<?> iterator = collection.iterator();
while (iterator.hasNext()){
System.out.println(iterator.next());
}
}
public static void main(String[] args) {
Collection<Integer> collection1 = new ArrayList<>();
Collection<Number> collection2 = new ArrayList<>();
Collection<Object> collection3 = new ArrayList<>();
//正确
printCollection1(collection1);
//正确
printCollection1(collection2);
//报错:Object为Number的父类,超过上限,泛型上限限定只能是Number或Number的子类
//printCollection1(collection3);
//报错:Integer为Number的子类,超过下限,泛型下限限定只能是Number或Number的父类
//printCollection2(collection1);
//正确
printCollection2(collection2);
//正确
printCollection2(collection3);
}
}