Rumah  >  Soal Jawab  >  teks badan

java - A是B的子类,为什么List<A>就不是List<B>的子类?

如题。为什么会是这样呢?

ringa_leeringa_lee2759 hari yang lalu937

membalas semua(7)saya akan balas

  • 迷茫

    迷茫2017-04-17 13:08:55

    注意对比的对象
    A是B的子类 是A与B在比较
    List<A>List<B>的子类 是List与List进行比较
    你可以通过List<? extend b>这样的定义 来进行限定操作

    balas
    0
  • ringa_lee

    ringa_lee2017-04-17 13:08:55

    因为都是List类,又没有继承关系

    balas
    0
  • 怪我咯

    怪我咯2017-04-17 13:08:55

    对象的继承代表了一种‘is-a’的关系,如果两个对象A和B,可以表述为‘B是A’,则表明B可以继承A。继承者还可以理解为是对被继承者的特殊化,因为它除了具备被继承者的特性外,还具备自己独有的个性。

    父类和子类,或叫做基类和派生类,其中子类继承父类的所有特性,同时还定义新的特性。

    balas
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:08:55

    List<A>的子类是
    class XXX extends List<A>

    balas
    0
  • ringa_lee

    ringa_lee2017-04-17 13:08:55

    Java里的泛型是通过 类型擦除 来实现的

    Java中的泛型基本上都是在编译器这个层次来实现的。在生成的Java字节码中是不包含泛型中的类型信息的。使用泛型的时候加上的类型参数,会在编译器在编译的时候去掉。这个过程就称为类型擦除。

    List <A> 和 List <B> 在编译完成以后,实际上指向的是同一份字节码
    并不存在 List <A> 或者 List <B> 这2种类型 ,当然就更谈不上什么子类的问题了.
    

    以下仅供参考 我C++不熟
    你不是和C++模板搞混了?
    C++的泛型实现方式不同

    在C++中 确实会为 List <A> 和 List <B> 生成2个class
    

    balas
    0
  • 巴扎黑

    巴扎黑2017-04-17 13:08:55

    因为List<A>.class不成立。
    泛型

    balas
    0
  • 大家讲道理

    大家讲道理2017-04-17 13:08:55

    一大堆回答都没讲到重点啊。。我来加点内容。这里涉及到两个概念:协变与逆变。(Covariance vs. Contravariance)

    简言之,如果List<S>复合类型是协变的,那么如果ST的子类,则List<S>也是List<T>的子类。如果List<S>是逆变的,结果颠倒,List<T>会变成List<S>的子类。

    但是Java里的泛型不实现以上两种行为的任意一种。。Java的泛型是不变的(Invariance)。

    为什么这么设计呢?先看一个数组的例子。在Java中,数组是协变的,于是Integer[]就是Number[]的子类了。于是我们能写出这样的代码:

    Integer[] a = new Integer[3];
    Number[] b = a;    // a的类型是Integer[],是Number[]的子类
    b[0] = 3.14;    // 运行时错误
    

    Java的类型安全(Type Safety)的保证已经被破坏了。Java会把数组的元素应有类型保存起来(Reification),保证能在运行时检测到这种非法操作。

    假设List是协变的,那么如下把Float放进Integer的代码:

    List<Integer> li = new ArrayList<Integer>(); 
    List<Number> ln = li;    // li的类型是List<Integer>,属于List<Number>的子类
    ln.add(new Float(3.1415));    // 不会有错误
    

    就能运行。而 @dkmeteor 也提到,Java的泛型采用了类型擦除,这样就没法保证List里会不会被塞进一个Float,因为在运行时List看到的全都是Object。因此为了防止这类事情发生,Java的泛型是不变的。

    那有没有办法在Java里用上协变或者逆变的泛型呢?答案是肯定的,需要在声明里加wildcard:

    // 1.协变范例
    List<? extends Number> num = new List<Double>();
    // 2.逆变范例
    List<? super Number> num = new List<Object>();
    

    但是在第一种情况中就不能呼叫参数里带有?的函数了,例如:

    class Container<E> {
        E data;
        public set(E data) {
            this.data = data;
        }
        public E get(E data) {
            return data;
        }
    }
    
    // 某方法中
    Container<? extends Number> num = new Container<Double>();
    num.set(new Float(3));    // 编译时错误
    

    这里同样是为了保证Type Safety。不能把Float传给Container<Double>

    同理,在逆变的时候就不能呼叫返回值带?的函数,除非接受返回值的变量类型是Object。

    Container<? super Number> num2;
    Number res = num2.get();    // 编译时错误
    

    部分来源:http://www.ibm.com/developerworks/cn/java/j-jtp01255.html

    balas
    0
  • Batalbalas