2015-09-22 39 views
1

为什么下面的代码在我尝试编译时会引起警告?使用泛型返回列表的接口导致警告

Bag.java:

import java.util.List; 

public interface Bag<T> { 
    public List<String> getOwnerNames(); 
} 

BagException.java:

public class BagException extends Exception { 

    public BagException(Bag badBag) { 
     super(buildMessage(badBag)); 
    } 

    private static String buildMessage(Bag badBag) { 

     // BagException.java:10: warning: [unchecked] unchecked conversion 
     //     List<String> owners = badBag.getOwnerNames(); 
     //               ^
     //  required: List<String> 
     //  found: List 
     List<String> owners = badBag.getOwnerNames(); 

     return "Something went wrong with the bag of " + String.join(", ", owners); 
    } 

} 

List<String> owners = badBag.getOwnerNames()buildMessage导致即使该方法被声明为返回List<String>警告。

看来非常奇怪的是,这些变化使报警消失:

  • buildMessage参数使用Bag<Integer> badBag代替Bag badBag

    private static String buildMessage(Bag<Integer> badBag) {

  • 在界面使用Bag代替Bag<T>

    public interface Bag {

我期待该方法getOwnerNames是类型的BagT的无关。如果您可以回答以下其中一个问题,这将有所帮助:

  • 为什么我会收到警告?
  • 除了压制它之外,我该怎么办?
+0

关于重复:现在我看到我一直在寻找错误的术语。我应该寻找“原始类型”或“通配符”。 – Markus

回答

1

您使用的是通过声明Bag没有为类的类型参数一个参数所谓的程序raw type。 Java编译器javac将处理原始类型,例如它是否不包含通用类型信息。这涉及作为原始类型的一部分的任何泛型类型,甚至包括不包含原始类型的类型变量的类型。 (在您的情况下,List<String>被视为原始List。)

因此,原始引用的Bag中的所有泛型都被视为删除。您也可以观察到,

String value = badBag.getOwnerNames().get(0); 

不会编译为原料Bag返回原List而不是List<String>。您收到的警告强调,您将这样的原始列表分配到通用List<String>可导致heap pollution的事实。

+0

+1有趣的是,IntelliJ上的自动完成说'getOwnerNames()'返回'List ',而如果你链接操作('get/add/...'),它清楚地表明它返回了一个raw名单。 –

+0

不幸的是,IDE经常会出现泛型类型错误。许多IDE应用了一种“部分擦除”,其中尽可能多的通用类型信息被擦除。但是,当扩展原始类型时,javac不会添加桥接方法,这会导致多态性混乱。 –

+0

这个答案很好地描述了问题所在。我可以想出解决方案(使用通配符'')和这个信息和引用的排队。这就是我接受这个答案的原因。 – Markus

-1

除了压制它之外,我能做些什么?

尝试:

public BagException(Bag<?> badBag) { 
    super(buildMessage(badBag)); 
} 

private static String buildMessage(Bag<?> badBag) { 
+0

为什么downvote?它回答了第二个问题:“除了压制它,我能做些什么呢?” – Puce

+0

这非常有帮助。我将在我的项目中使用它。 – Markus