您的位置:首页 > 编程语言

第二十三条:不要在新代码中使用原生类型

2016-09-03 16:14 281 查看

一、泛型的术语

类型参数:public class Request<E>{} 其中的E就是类型参数。
参数化类型:List<String> 这叫做参数化类型。
原生类型:List  没有泛型的类,叫做原生。

补:在JAVA中是不推荐使用原生类型的,但是为什么不将原生类型去掉?
因为泛型引入是在JAVA产生的20年后,为了向上兼容以前的代码,所以就保持了原生类型。

二、泛型的优点

①、能够在编译期间报错
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> stringList = new ArrayList<>();
stringList.add("asd");
stringList.add(1);//报错:无法存储Integer类型
}
而以前的代码只能够调用的时候,发现ClassCastException的错误

②、能够隐式转换(就是我输入的是String,那么我获取到的数据也是String)
public static void main(String[] args) {
// TODO Auto-generated method stub
List<String> stringList = new ArrayList<>();
stringList.add("asd");

for(String str : stringList){
System.out.println(str);
}
}
以前的代码,存储的都是Object类型,所以获取之后需要自己强制转换。

三、泛型的一些特征

①、子类化规则
List<String> != List<Object> 虽然它们同为List.class类。
这很好理解,因为里面存储的内容不一样,那么这个容器的类型也就不一样。(比如说茶壶和酒壶)
但是这个机制同时会引发一个问题:
Integer是Number的子类,但是List<Number> list != new List<Integer>()。
按道理来说List<Number> 应该是List<Integer>的父类,应该可以向上转型才是呀,可是根本无法使用。
这种方式是对的,因为当向上转型之后,就表示可以装入Number的子类,比如double,但是double并不是Integer的子类,不能放在List<Integer>的容器中。
例:
public static void main(String[]args){
List<Number> list = new ArrayList<Integer>();
double a = 1.34;
list.add(a);
}
这样其实为List<Integer>的容器就装入了Double类的成员变量,这样就违反了类型约束的规则。

②、原生类型可支持所有泛型
List<String> stringList = new ArrayList<>();
List<Object> objList = new ArrayList<>();

//"大哥"我能支持所有类型赋值
List list = objList;
list = stringList<span style="font-family: Arial, Helvetica, sans-serif;">;</span>
//并且还能装填各种数据
list.add(1);
list.add("string");
list.add(new Object());
//List<Object> 我也能装填各种类型,而且我还有类型检验
objList.add(1);
objList.add("string");
objList.add(new Object());

但是如果使用原生类型,就代表放弃了类型安全检验。
使用的时候就会产生错误:
String str = stringList.get(0);
就会报错(ClassCastException):

Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

at Main.main(Main.java:12)

③、无限通配符(?)
JAVA为了解决原生类型不安全的问题,所以产生了无限通配符 来解决这个问题。
使用:只需要List 变成List<?>就可以了。
那么无限通配符真的起到作用了吗?
从意义上讲,是的。
因为List<?>被认为是安全的,而List被认为是不安全的。
至少List<?>没有警告 - -。
但是,事实上还是破坏了类型约束条件。
所以,为保证类型安全,Collection<?>是无法存储null以为的数据的。

④、必须使用原生类型的情形。
原因:因为泛型具有擦除的问题。
什么叫做擦除:指的是,在运行期间,使泛型可以使没使用泛型的代码之间互相的转换。

情形1、使用类文字的时候必须使用原生类型
例:可以使用List.class、String[].class、int.class
但是却不可以使用List<String>.class,List<?>.class
因为,JAVA的擦除会导致List<String>.class其实还是List.class,那么List<String>、List<Object>本不相同的东西,就变成一样了。

情形2、使用instanceof是违法的
例:
List<String> list = new ArrayList<>();
if (list instanceof List<String>) {}//由于擦除问题,这样同样是非法的。
所以一般方式是这样处理的:
if (list instanceof List){
  List<?> myList = (List<?>) list;//保证类型安全
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: