为什么我可以返回我的列表未指定类型的列表<t>返回类型?

时间:2016-05-28 20:00:51

标签: java generics

鉴于以下课程......

package whoop.deduper;

/**
 * @author deduper
 *
 */
public class Foo {

}
package whoop.deduper;


import java.math.BigDecimal;
import java.util.Iterator;
import java.util.List;

/**
 * @author deduper
 *
 */
public class FuBar {

    public int fuBar( ){

        Bar bar = new Bar();

        List<Foo> foos = bar.foos();

        int baz = 0;

        for ( Iterator iterator = foos.iterator( ); iterator.hasNext( ); ) {

            BigDecimal foo = (BigDecimal) iterator.next( );

            baz = foo.intValue( );

            return baz;

        }

        return baz;     

    }

}
package whoop.deduper;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
 * @author deduper
 *
 */
public class Bar {

    public <T extends Foo> List<T> foos( ) {

        List sketchy = new ArrayList();

        sketchy.add( BigDecimal.TEN );

        return sketchy;
    }

}
package whoop.deduper;

import static java.lang.System.out;

/**
 * @author deduper
 *
 */
public class EffedUp {

    /**
     * @param args
     */
    public static void main( String[ ] args ) {

        int effedUp = new FuBar().fuBar( );

        out.println(effedUp + " — But it works!");

    }

}

...为什么这甚至有效?我的意思是,我本来期望在那里的某个地方有ClassCastException!为什么不存在?

请有人能指出一份清楚的书面解释,说明这里发生了什么吗?

提前致谢。

2 个答案:

答案 0 :(得分:1)

拥有List<Foo>类型的变量并不能保证您实际上有一个Foos列表。你只会确保当你试图将Foos拉出来时,你不是,你的迭代器不是Iterator<Foo>而你不会在任何地方施放Foo。如果您让编译器为您进行转换,那么它将按预期中断。

 List<Foo> foos = bar.foos();

  int baz = 0;

  for (Foo foo : foos) {
     System.out.println(foo); // ClassCastException
  }

如果你使用如上所示的“normal”路径,编译器将自己成为迭代器并将每个元素强制转换为Foo,因此如果列表不为空,上述代码将失败。

您的代码演示了raw-types有多糟糕以及为什么应该始终避免它们。

答案 1 :(得分:-1)

  List l = new ArrayList();
  List<Integer> ints = l;

当您完成作业时,您将告诉Java将l的地址放在ints中,仅此而已。这种情况发生在运行时,从代码中删除泛型。

当编译器尝试识别与类型相关的可能错误时,编译器在编译时使用泛型。它不会在编译时崩溃,因为他不知道列表中存储了什么值,因为没有指定。当列表包含意外元素时,它会在ClassCastException运行时崩溃(因为只有在运行时才会有对象)。

我无法弄清楚他们为何在编译时允许这种情况发生的原因。如果编译器遇到类似这样的事情,我会发现编译错误。而不是错误,你会收到警告。

当您完成作业时,您只需说I give you a list, doesn't matter what it has inside, you just store it

作为建议,请始终指定列表的类型。在您的情况下List<T>。请记住这一点,只要您不需要包含许多对象类型的列表,根据我的经验,这种类型很少见。