为什么这段代码不可编译

时间:2015-07-14 07:52:43

标签: java generics

这里是一小段代码,我不明白为什么javac无法编译它。我想念的是什么?有没有错误?

public class HelloWorld<T> {
    private static enum Type {
    }

    private T value;
    private List<Type> types = new ArrayList<>();

    public T getValue() { return value; }

    public List<Type> getTypes() { return types; }

    public static void main( String[] args ) {
        for ( Type type : new HelloWorld().getTypes() ) { // Error: Type mismatch: cannot convert from element type Object to HelloWorld.Type

        }
    }
}

为什么getTypes()会在Object列表中返回Type(原始)列表?

Link to online compiler

4 个答案:

答案 0 :(得分:3)

这对我来说似乎是编译器限制。 getTypes始终返回List<Type>,因此使用原始HelloWorld类型应该没有任何区别。

尽管如此,这两种解决方案中的任何一种都将克服错误:

  1. 创建参数化类型HelloWorld而不是原始类型:

    for (Type type : new HelloWorld<Integer>().getTypes() ) { // any type will do, I chose 
                                                              // Integer arbitrarily to show
                                                              // that it doesn't matter
    
    }
    
  2. 在使用List之前使用局部变量存储List:

    List<Type> types = new HelloWorld().getTypes();
    for (Type type : types) { 
    
    }
    
  3. 无论如何,参数化类型应始终优先于原始类型,因此我将使用第一个解决方案(任何类型参数在您的类中都有意义)。

答案 1 :(得分:1)

在尝试使用代码时,我注意到了一些非常有趣的内容。为了删除编译器错误:

  

错误:类型不匹配:无法从元素类型Object转换为   HelloWorld.Type

由于声明返回的元素属于Object类型,因此我决定将其强制转换为List<Type>,如下所示:

public static void main( String[] args ) {
    for ( Type type : (List<Type>)new HelloWorld().getTypes() ) { 

    }
}

这已成功编译并发出警告,因此我使用-Xlintjavac查看警告是什么,我发现了以下内容:

HelloWorld.java:15: warning: [rawtypes] found raw type: HelloWorld
        for ( Type type : (List<Type>)new HelloWorld().getTypes() ) {
                                          ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
HelloWorld.java:15: warning: [unchecked] unchecked cast
        for ( Type type : (List<Type>)new HelloWorld().getTypes() ) {
                                                               ^
  required: List<Type>
  found:    List
2 warnings

我惊讶地发现第二次警告。它声明必填List<Type>,但找到List RAW TYPE 。因此,这意味着如果初始化原始类型对象并调用返回具有泛型的变量的方法,则此变量也将转换为 RAW TYPE 。为了测试这个,我实现了一个类HelloWorldTest

public class HelloWorldTest<T>{
    private T t;

    public HelloWorldTest(T t){
        this.t = t;
    }

    public T getT(){
        return t;
    }
}

然后我更改了您的代码以将条件测试为:

public class HelloWorld<T> {

    private HelloWorldTest<Integer> test = new HelloWorldTest<>(1);

    public HelloWorldTest<Integer> getTest(){
        return test;
    }

    public static void main( String[] args ) {
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
    }
}

这个编译成功,但有警告,所以使用-Xlint开关编译我得到以下警告:

HelloWorld.java:10: warning: [rawtypes] found raw type: HelloWorld
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
                                            ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
HelloWorld.java:10: warning: [unchecked] unchecked conversion
        HelloWorldTest<Integer> hello = new HelloWorld().getTest();
                                                                ^
  required: HelloWorldTest<Integer>
  found:    HelloWorldTest
2 warnings

所以,我们在这里也发现HelloWorldTest已经转换为原始类型。

最后我们可以推断出:如果初始化原始类型对象并调用返回具有泛型的变量的方法,则此变量也将转换为RAW TYPE

现在我换了

    HelloWorldTest<Integer> hello = new HelloWorld().getTest();

    Integer hello = new HelloWorld().getTest().getT();

正如所料,我收到了错误:

HelloWorld.java:10: error: incompatible types: Object cannot be converted to Integer
        Integer hello = new HelloWorld().getTest().getT();
                                                       ^
1 error

最后,如果将HelloWorld类的实现中的main方法替换为:

    public static void main( String[] args ) {
        String hello = (String) new HelloWorld().getTest().getT();
    }

成功编译只有警告:

HelloWorld.java:10: warning: [rawtypes] found raw type: HelloWorld
            String hello = (String) new HelloWorld().getTest().getT();
                                        ^
  missing type arguments for generic class HelloWorld<T>
  where T is a type-variable:
    T extends Object declared in class HelloWorld
1 warning

这是非常误导的,因为这肯定会遇到运行时错误,并再次说明了泛型中 RAW TYPE 的危险。

答案 2 :(得分:0)

更改for循环以为类添加泛型类型:

例如:我在这里以'Type'为例。

for ( Type type : new HelloWorld<Type>().getTypes() ) {

编辑:

它可能是'String'以及评论中指出的。(谢谢你)。 在您的情况下,它应该是该类所需的实际类型。

这个想法是缺少需要添加的泛型类型。

答案 3 :(得分:0)

main方法中:

for ( Type type : new HelloWorld().getTypes() ) {//Here also you did not mention the type for the new object since 
}

在main方法中尝试:

for ( Type type : new HelloWorld<Type>().getTypes() ) {

}