今天来看提示二十六:不要使用原始类型。
一个类或接口,它的声明有一个或多个类型参数,被称之为泛型类或泛型接口。
每个泛型定义了一组参数化类型,它们由类或接口名称组成,后跟一个与泛型类型的形式类型参数相对应的实际类型参数的尖括号列表。
每个泛型定义了一个原始类型,它是没有任何类型参数的泛型类型的名称。 原始类型的行为就像所有的泛型类型信息都从类型声明中被清除一样。 它们的存在主要是为了与没有泛型之前的代码相兼容。
如果你使用原始类型,则会丧失泛型的所有安全性和表达上的优势。原始类型就是不加尖括号的形式,这样逃避了泛型检查,会把一些原来在编译阶段就能暴露的错误拖到执行阶段才暴露出来。
List string1 = new ArrayList<String>();
string1.add(new Date()); //不会报错
string1.add("234");
List<String> string2 = new ArrayList<String>();
string2.add(new Date()); //编译会报错
string2.add("234");
原始类型 List 和参数化类型 List<Object> 之间的区别是前者已经选择了泛型类型系统,而后者明确地告诉编译器,它能够保存任何类型的对象。比如List<Object> list = new ArrayList<String>();
这行代码就会报错,如果用原始类型就没有问题。文中举了这样一个例子:
public static void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
String s = strings.get(0); // Has compiler-generated cast
}
private static void unsafeAdd(List list, Object o) {
list.add(o);
}
直接把这个对象赋值给String就会报错,但是我发现只要不把这个对象转成String就没有问题,下面的代码就可以正常运行。
public void main(String[] args) {
List<String> strings = new ArrayList<>();
unsafeAdd(strings, Integer.valueOf(42));
System.out.println(strings);//[42]
List<Object> objects = new ArrayList<>();
objects.addAll(strings);
System.out.println(objects);//[42]
System.out.println(objects.get(0)); //42
}
无限制通配符 Set<?> 与原始类型 Set 更加安全,你不能把任何元素(除 null 之外)放入一个 Collection<?> 中。
必须使用原生态类型的场景:
- 在类字面值(class literals)中使用原始类型。
- 在使用instanceof操作符的时候。
网友评论