一.为什么要出现泛型
Java集合有一个缺点——把一个对象丢进集合里之后,集合就会忘记这个对象的数据类型,
当程序从集合中取出对象之后,当再次取出该对象时,该对象的编译类型就变成了Object类型(其运行时类型没变)。
集合的设计者把集合设计成能保存任何类型的对象,是要求拥有更好地通用性,但却带来了以下问题:
1.可能会引发一些问题,例如:想创建一个只能保存Dog类型的对象,但程序也可以轻易地将Cat对象保存进去;
2.把对象丢进集合时,丢失了对象的状态信息,集合只知道他称装的是Object,因此取出集合之后通常还需要进行
类型转换,使得代码臃肿,还可能引发ClassCastException异常
例如:
package genericity;
import java.util.ArrayList;
import java.util.List;
public class ListErr {
public static void main(String[] args) {
List strList=new ArrayList();
strList.add("I");
strList.add("Love");
strList.add("java");
strList.add(8);//不小心将一个Integer对象丢进了集合
strList.forEach(str->System.out.println(((String)str).length()));//②
}
}
在②处,程序遍历到8时,试图将一个Integer类型对象转成String类型,将引发异常。
二.使用泛型
因此在JDK1.5之后,java引入了“参数化类型的概念”,允许程序在创建集合石指定集合元素的类型,
参数化类型被称为泛型,增加了泛型的集合,完全可以记住元素的类型,
并且可以在编译时检查集合中的元素类型,如果试图向集合中添加不满足类型要求的对象,编译就会提示错误。
使用泛型的方法是:在集合接口,类后增加尖括号,尖括号里放一个数据类型,即表明只能保存特点类型的对象
如下是使用泛型对上一个程序进行的改进
package genericity;
import java.util.ArrayList;
import java.util.List;
public class GenericList {
public static void main(String[] args) {
List<String> strList=new ArrayList<String>();
strList.add("I");
strList.add("Love");
strList.add("java");
//strList.add(8);//②
strList.forEach(str->System.out.println(str.length()));//③
}
}
上面程序的strList只能保存字符串对象,不能使用其他类型的对象
在②处会产生编译错误,不让添加Integer类型
而且在③处不再需要进行强制类型转换,因为strList能记住它所有的集合元素都是String类型
三.Java7泛型的菱形语法
Java7之前,如果使用了带泛型的接口,类定义变量,那么调用构造器对象是构造其也必须带泛型,多余。
Java7之后,允许在构造器之后不需要带完整的泛型信息,只需要给出有一对尖括号(<>)
例如:
<span style="font-family:SimSun;font-size:18px;">package genericity;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class DiamondTest {
public static void main(String[] args) {
List<Integer> grades=new ArrayList<>();
Map<String,List<Integer>> students=new HashMap<>();
grades.add(100);
grades.add(100);
students.put("本大爷", grades);
students.forEach((key,value)->System.out.println(key+"-->"+value));
}
}
</span>