Java5增加泛型支持,很大程度上是为了让集合记住其元素的数据类型,在此之前不用泛型的话,一旦把一个对象放进Java集合中,集合就会忘记对象的类型,把所有的对象当成Object类型处理,从集合里取出对象后,还需要进行强制类型转换
增加了泛型支持后的集合,完全可以记住集合中元素的类型,并且在编译时检查集合中元素的类型,如果试图向集合中添加不满足类型要求的对象,编译器就会提示错误,增加泛型的集合让代码更简洁更健壮
泛型基础
import static java.lang.System.*;
public class ListErr
{
public static void main(String[] args)
{
// 创建一个只想保存字符串的List集合
List strList = new ArrayList();
strList.add("两岸猿声啼不住");
strList.add("轻舟已过万重山");
strList.add(5);
// 引发ClassCastException异常,程序试图将Integer对象转换为String类型
strList.forEach(str -> out.println(((String)str).length()));
}
}
在Java5之后,引入了“参数化类型(parameterized type)”,它被称之为泛型(Generic)
import static java.lang.System.*;
public class GenericList
{
public static void main(String[] args)
{
//创建一个只想保存字符串的List集合
List<String> strList = new ArrayList<String>();
strList.add("古道西风瘦马");
strList.add("断肠人在天涯");
strList.add(5);
strList.forEach(str ->out.println(strList.length()));
}
}
在集合接口、类后增加尖括号,尖括号里放一个数据类型,表明该集合接口、集合类只能保存这个数据类型的对象
- List:该List是带一个类型参数的泛型接口,类型参数是String
- ArrayList():创建这个ArrayList对象时也指定了类型参数
- 也因此最后的out.println里已经不需要进行强制类型转换,因为strList已经记住了该集合里对象的类型是String类型
菱形语法
在Java7之前,如果使用带泛型的接口、类定义变量,那么调用构造器创建对象时构造器的后面也必须带泛型,例如:
List<String> strList = new ArrayList<String>();
Map<String, Integer> score = new HashMap<String, Integer>();
从Java7开始,Java允许在构造器后不要带完整的泛型信息,只要给出一堆尖括号即可
List<String> strList = new ArrayList<>();
Map<String, Integer> score = new HashMap<>();
两个尖括号里什么都不放,并排挨着放一起非常像一个菱形,这种语法也就被称为菱形语法,实际上对原有的泛型并没有改变,只是更好的进行了简化
import java.util.*;
import static java.lang.System.*;
public class DiamondTest
{
public static void main(String[] args)
{
// Java自动推断出ArrayList的<>里应该是String
List<String> books = new ArrayList<>();
books.add("铁道旁赤脚追晚霞");
books.add("玻璃珠铁壳英雄卡");
// 遍历books集合,集合元素就是String类型
books.forEach(ele -> out.println(ele.length()));
// Java自动推断出HashMap的<>里应该是String, List<String>
Map<String, List<String>> schoolsInfo = new HashMap<>();
// Java自动推断出ArrayList的<>里应该是String
List<String> schools = new ArrayList<>();
schools.add("这是个旅途");
schools.add("一个叫做命运的慢慢旅途");
schoolsInfo.put("炊烟袅袅升起", schools);
// 遍历Map时,Map的key是String类型,value是List<String>类型
schoolsInfo.forEach((key, value) -> out.println(key + "-->" + value));
}
}
import static java.lang.System.*;
// 定义一个带泛型声明的接口
interface Foo<T>
{
void test(T t);
}
public class AnnoymousDiamond
{
public static void main(String[] args)
{
// 指定Foo类中泛型为String
Foo<String> f = new Foo<>()
{
// test()方法的参数类型为String
public void test(String t)
{
out.println("test方法的t参数为:" + t);
}
};
// 使用泛型通配符,此时相当于通配符的上限为Object
Foo<?> fo = new Foo<>()
{
// test()方法的参数类型为Object
public void test(Object t)
{
out.println("test方法的Object参数为:" + t);
}
};
// 使用泛型通配符,此处写法表示通配符的上限为Number
Foo<? extends Number> fn = new Foo<>()
{
// 此时test()方法的参数类型为Number
public void test(Number t)
{
out.println("test方法的Number参数为:" + t);
}
};
}
}