美文网首页Effective Java
第23条 请不要在新代码中使用原生态类型

第23条 请不要在新代码中使用原生态类型

作者: 慧执行 | 来源:发表于2017-05-27 14:44 被阅读0次

    声明中具有一个或者多个类型参数的类或者接口,就是泛型类或者接口。
    没有使用泛型的类型就是原生态类型。

    每种泛型定义一组参数化的类型,结构为:类或者接口的名称<泛型类型>
    如List<String>(读作"字符串列表")是一个参数化的类型,表示元素类型为String的列表。

    在jdk1.5之前没有泛型的概念,在1.5发行版本中增加了泛型。在没有泛型之前,从集合中读取到的每一个对象都必须进行转换。如果有人不小心插入了类型错误的对象,则在运行时的转换处理才会报错。有了泛型之后,可以告诉编译器每个集合中接受哪些对象类型,编译器自动地为你的插入进行转换,并在编译时告知是否插入了类型错误的对象。

    使用泛型之前:
    定义了一个集合,想要集合中包含的是stamp的实例
    private final List stamps = new ArrayList();
    在往集合中插入对象时,如果不小心将一个coin对象放进了stamp集合中,编译不会报错。
    stamps.add(new Coin());
    运行到从stamp集合中获取coin时才会报错:
    for(Object o : stamps){
    Stamp s = (Stamp)o;
    }

    使用泛型:
    private final List<Stamp> stamps = new ArrayList<Stamp>();
    告诉了编译器stamps集合应该只包含Stamp实例,当放入其他类型时,会编译报错。
    stamps.add(new Coin());

    使用泛型还有一个好处就是不需要手动做类型转换,编译器会替你隐式转换。
    for(Stamp s : stamps){
    }

    Iterator<Stamp> i = stamps.iterator();
    while(i.hasNext()){
    Stamp s = i.next();
    }

    当然如果不提供类型参数,使用原生态类型,也仍然是合法的,但是不应该这么做,这样失掉了泛型在安全性和表述性方面的所有优势。目前java保留了原生态类型是为了提供兼容性,因为在泛型出来前已经有大量没有使用泛型的代码。为了这些代码保持合法,并且能够与使用泛型的新代码互用。因此在新代码中不应该使用原生态类型。

    如果想插入任意对象,可以使用List<Object>,那么它和原生态类型List有什么区别呢?
    原生态类型逃避了泛型检查,而List<Object>则明确告诉编译器,它能够持有任意类型的对象。
    如List<String>可以传递给类型List的引用,而不能传递给类型List<Object>的引用。因此使用原生态类型会失掉类型安全性。
    如原生态类型:运行时会报类型转换异常。


    2.jpg

    而使用参数化类型List<Object>: 在编译时就会报错


    1.jpg

    如果不确定或不在乎集合元素的类型时,可以使用无限制的通配符类型,以?来表示某种类型,如Set<?>,表示某个类型的集合。
    通配符类型是安全的,原生态类型则不安全,可以将任何元素插入到原生态类型集合中,因此很容易破坏集合类型的约束条件。但不能将任何元素(除了null)之外放到Collection<?>中,插入时会有编译错误。

    3.jpg

    编译错误:
    The method add(capture#5-of ?) in the type Set<capture#5-of ?> is not applicable for the arguments (int)

    但无限制的通配符类型局限性很大,无法将任何元素放进Collection<?>中,而且根本无法猜测你会得到哪种类型的对象,解决这类问题,可以使用泛型方法(27条)或者有限制的通配符类型(28)条来解决。

    不要在新代码中使用原生态类型,这条规则有两个小小的例外:
    1.在类文字中必须使用原生态类型。如:
    List.class, String[].class, int.class都是合法的, 但是List<String>.class 和 List<?>.class则不合法。
    2.在instanceof操作符关联的类型使用原生态类型。如
    if (o instanceof Set) {
    Set<?> m = (Set<?>)o;
    }
    由于泛型信息可以在运行时被擦除,因此在参数化类型而非无限制通配符类型上使用instanceof操作符是非法的。
    使用无限制通配符类型代替原生态类型,对instanceof操作符的行为不会产生任何影响,这种情况<?>就显得多余。
    因此instanceof操作符关联的类型使用原生态类型。

    总结:使用原生态类型会在运行时导致异常,因此不要在新代码中使用。除非是类文字中或者instanceof中才使用原生态类型。
    Set<Object>是参数化类型,表示可以包含任何对象类型的集合。Set<?>是通配符类型,标示只包含某种未知对象类型的集合。Set则是原生态类型。前两种是安全的,最后一种不安全。

    相关文章

      网友评论

        本文标题:第23条 请不要在新代码中使用原生态类型

        本文链接:https://www.haomeiwen.com/subject/lmxtfxtx.html