一、泛型简单应用
通过一个小例子看一下泛型的作用
package cn.itcast;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
public class Java_36_Generic {
public static void main(String[] args) throws Exception {
/*不添加泛型 */
ArrayList collection1 = new ArrayList();
collection1.add(1);
collection1.add("abc");
//取出时就要强制类型转换
int i = (Integer)collection1.get(0);
System.out.println(i);
/*添加泛型 */
ArrayList<String> collection2 = new ArrayList<String>();
collection2.add("abc");//存放时只能放置String类型
//取出时不用强制类型转换
String str = collection2.get(0);
/*泛型在反射的应用*/
Constructor constructor1 = String.class.getConstructor(StringBuffer.class);
String str1 = (String) constructor1.newInstance(new StringBuffer("abc"));
Constructor<String> constructor2 = String.class.getConstructor(StringBuffer.class);
String str2 = constructor2.newInstance(new StringBuffer("abc"));
}
}
通过以上可以得到:
没有泛型时,只要是对象,不管是什么类型的对象,都可以存储进同一个集合中;
使用泛型集合,可以将一个集合中的元素限定为一个特定类型,集合中只能存储同一个类型的对象,这样更安全;
并且当从集合获取一个对象时,编译器也可以知道这个对象的类型,不需要对类型进行强制类型转换,这样更方便。
二、泛型的作用
泛型是提供给Java编译器使用的,可以限定集合中的输入类型,让编译器挡住源程序中的非法输入,编译器编译带类型说明的集合是会去掉类型信息,使程序运行效率不受影响,对于参数化的泛型类型,getClass(),方法的返回值和原始类型完全一样。由于编译器生成的字节码会去掉泛型的类型信息,只要能跳过编译器,就可以往某个泛型集合中加入其他类型的数据。例如,用反射得到集合,再调用其他add方法即可。
package cn.itcast;
import java.util.ArrayList;
public class Java_37_Generic {
public static void main(String[] args) throws Exception {
ArrayList<Integer> collection1 = new ArrayList<Integer>();
ArrayList<String> collection2 = new ArrayList<String>();
//创建的两个不同泛型的对象,指向同一份字节码文件
System.out.println(collection1.getClass() == collection2.getClass());//true
//跳过编译器,往<Integer>类型集合中添加String类型数据。
collection1.getClass().getMethod("add", Object.class).invoke(collection1, "abc");
System.out.println(collection1.get(0));//abc
}
}
三、泛型的语法
(1)ArrayList<E>类定义和ArrayList<Integer>类引用中设计如下术语:
整个成为ArrayList<E>泛型类称
ArrayList<E>中的E成为类型变量或者类型参数
整个ArrayList<Integer>成为参数化的类型
ArrayList<Integer>中的Integer成为类型参数的实例或实际类型参数
ArrayList<Integer>中的<>念作typeof
ArrayList成为原始类型
(2)参数化类型与原始类型的兼容性
参数化类型可以引用一个原始类型的对象,编译器报警告
Collectionc = new Vector<String>();
原始类型可以引用一个参数化类型的对象,编译报告警告,例如:
Collectionc = new Vector<String>();
(3)参数化的类型不考虑继承关系:
Vector<String>v = new Vector<Object>();
Vector<Object>v = new Vector<String>();
(4)在创建数组实例时,数组的元素不能使用参数化的类型。
(5)泛型中的?通配符
①使用?通配符可以引用其他各种参数化的类型,?通配符定义的变量主要用作引用,可以调用与参数化无关的方法,不能调用与参数化有关的方法。
package cn.itcast;
import java.util.ArrayList;
import java.util.Collection;
public class Java_38_Generic {
public static void main(String[] args) {
//定义两个不同泛型的集合,并添加元素
ArrayList<String> collection1 = new ArrayList<String>();
ArrayList<Integer> collection2 = new ArrayList<Integer>();
collection1.add("abc");
collection2.add(1);
collectionPrint(collection1);
collectionPrint(collection2);
}
//定义集合输出方法
private static void collectionPrint(Collection<?> cols) {
for(Object obj : cols) {
System.out.println(obj);
}
}
}
②泛型中的?通配符扩展
限定通配符的上边界,如:
Vector<?extends Number> x = new Vector<Integer>();
限定通配符的下边界,如:
Vector<?super Integer> x = new Vector<Number>();
注意:限定通配符总是包括自己。
四、泛型集合的综合应用案例
要求打印出HashMap集合中的所有元素。
package cn.itcast;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
public class Java_39_GenericDemo {
public static void main(String[] args) {
//定义一个HashMap
Map<Integer, String> hashMap = new HashMap<Integer, String>();
//向集合中添加元素
hashMap.put(1, "zhangsan");
hashMap.put(2, "lisi");
hashMap.put(3, "wangwu");
//通过EntrySet取出集合中的关系
//注:Set<Map.Entry<K,V>> entrySet() 返回此映射中包含的映射关系的 Set视图
Set<Map.Entry<Integer, String>> entrySet = hashMap.entrySet();
//(1)通过增强for()迭代输出。
for(Map.Entry<Integer, String> entry : entrySet)
System.out.println("key:"+entry.getKey()+"\tvalue:"+entry.getValue());
//(2)通过Interator迭代输出
Iterator<Map.Entry<Integer, String>> it = entrySet.iterator();
while(it.hasNext()) {
Map.Entry<Integer, String> me = it.next();
System.out.println("key:"+me.getKey()+"\tvalue:"+me.getValue());
}
}
}
通过以上对泛型有了初步的理解与掌握,在下一步的学习中进一步加强,