zoukankan      html  css  js  c++  java
  • Java泛型:List<?>与List的区别

     

    为什么说List<?>是type-safe而List不是type-safe的?

    1、List<?>

      compiler看到了你使用了wildcard ?,那么相当于你对compiler说:“我不知道这个List里面的element的runtime-type是什么,如果我尝试对这个list或者list中取出来的object做一些type-specific的操作,你要给我一个compile-time-error来提醒我”。这样就导致了2个结果:

      1.1 list.get()返回类型为?,所以你只能用Object接收,Object足以确保type-safe,因为java中任何class都是Object的subclass。(当然,如果你非要使用类型强制转换,转换成什么阿猫阿狗的class,也没人拦得住你,对此只能说“编译器尽力了,你行你上啊”,反正ClassCastException什么的最有爱了)

      2.2 list.put()除了null以外,任何参数都不接收。这也足以确保list中类型的type-safe,要知道,java的泛型的implementation是基于ERASURE(擦除)的,举个具体的例子,LinkedList<E>的内部数据结构肯定是基于Node<E>,那么一个Node有2个field,E element和Node<E> next,而实际上在runtime环境中,LinkedList<String>中的Node并不是Node<String>,仅仅是Node,Node里面的element的类型也不是String,仅仅是Object,也就是说,compile-time的type-information都被抹除了(Quote: For backward-compatibility)。试想这么一个情景,Tom传了一个List<Dog>给Mike,Mike的interface是List<?>,Mike往list中放了一个Cat(假设compiler没有阻止Mike),然后Tom取出该List中所有的object并当成Dog使用(compiler会自动加上类型转换的代码——which is how java generics worked),然后Tom就悲剧地得到了一个ClassCastException——这就是为什么除了null其他参数都不接收的原因——阻止Mike随便放东西进去。

    2、List

      raw-type就是这么个情况,相当于你对compiler说:“我并不在乎这个List里面的element的runtime-type是什么,不管我怎么操作这个list或者list中取出来的object,你都别管,实在看不过去就给我个warning就行了”。这种情况下:

      2.1 list.get()返回类型为Object,当然,也是type-safe的(如果你不强制转换的话)

      2.2 list.put()的参数类型为Object,也就是说,你爱往里面放什么object就放什么object,还是上面那个例子,就算Tom给Mike的是List<String>,但由于Mike的interface是List,所以Mike放个BigInteger甚至什么Cat、Dog,compiler都不会阻止Mike(但是,要知道,Mike是无法得知其他人会怎么使用这个List的,比如说Mike无法得知Tom相信编译器确保了list中的object都是String,但是由于Mike的raw-type interface,Tom就难免吃ClassCastException咯)

    举个具体的例子:

    复制代码
    class Dog {
        public void bark() {
        }
    }
    
    class Cat {
        public void meow() {
        }
    }
    
    public class Foo {
        
        public static void foo1(List<?> list) { // Java generics are implemented upon ERASURE, so the runtime-type of elements in List<?> and List are both Object.
            if (list.isEmpty()) {
                return;
            }
            Object o = list.get(0); // Type safe if you don't do DOWN-CAST
            // list.add(new Dog()); // Won't compile
        }
        public static void foo2(List list) {
            if (list.isEmpty()) {
                return;
            }
            Object o = list.get(0); // Type safe if you don't do DOWN-CAST
            list.add(new Cat()); //! Compiler won't stop you, just gives you a little complaint
        }
        public static void main(String[] args) {
            List<Cat> cats = new LinkedList<Cat>();
            cats.add(new Cat());
            List<Dog> dogs = new LinkedList<Dog>();
            dogs.add(new Dog());
            
            foo1(cats); // relatively type-safe
            foo2(dogs); // dangerous
            
            for (Cat cat : cats) { // Cast from Object to Cat
                cat.meow();
            }
            
            for (Dog dog : dogs) { //! Cast from Object to Dog, ClassCastException
                dog.bark();
            }
        }
    }
    复制代码
  • 相关阅读:
    FastAPI框架
    bitmap去重与布隆过滤器
    MongoDB
    分布式爬虫
    scrapy 请求传参
    Scrapy 对接selenium
    Scrapy 去重源码分析
    [Python]网络小说爬取、爬虫
    学习进度报告【第八周】
    [opencv]图像处理-边缘检测
  • 原文地址:https://www.cnblogs.com/aipan/p/7511999.html
Copyright © 2011-2022 走看看