Java Generics - 令人困惑的行为

时间:2014-08-16 04:42:59

标签: java generics

我无法理解为什么我在这里收到编译错误。让我分享一些简单的代码。以下代码块正常工作:

public class Test {
  public static void main(String[] args) {
    String[] arr = new String[0];
    MethodA(arr);
  }

  public static <E> void MethodA(E[] array) {
    Integer[] intArray = new Integer[0];
    MethodB(array, intArray);
  }

  public static <E> void MethodB(E[] array, E[] secondArray) {
    //Stuff
  }
}

当我向MethodB添加一个新的通用List参数时,问题出现了,从MethodA调用它:

public class Test {
  public static void main(String[] args) {
    String[] arr = new String[0];
    MethodA(arr);
  }

  public static <E> void MethodA(E[] array) {
    Integer[] intArray = new Integer[0];
    List<E> someList = new ArrayList<E>();
    MethodB(array, intArray, someList);
  }

  public static <E> void MethodB(E[] array, E[] secondArray, List<E> list) {
    //Stuff
  }
}

这给了我以下错误:

  

线程中的异常&#34; main&#34; java.lang.Error:未解决的编译问题:       Test类型中的方法B(E [],E [],List)不适用于参数(E [],Integer [],List)

似乎告诉我将参数从E []更改为Integer [],这很奇怪,因为在我引入List参数之前它并没有抱怨这样的事情。再一次,我觉得我必须在某个地方犯一个愚蠢的错误,但我无法弄明白。任何帮助,将不胜感激!谢谢!

3 个答案:

答案 0 :(得分:7)

在第一个示例中,您使用MethodBString[]来呼叫Integer[]

由于数组是“协变的” - 例如,您可以将String[]强制转换为Object[],因此它会调用MethodB的版本Object

在第二个示例中,它类似,但您也有一个List<E>。通用类以与数组相同的方式工作 - 您无法List<String>转换为List<Object>。因此,对于E Object(或除了MethodA中的任何E之外的任何东西),它将无效,因为那时第三个参数无法转换,并且对于E来说它也是无效的String从那时起第一个参数无法转换。因此,没有适用于E的类型。

注意:如果您在String中将Integer更改为main,即使E可能是Integer,它仍然无法编译。那是因为编译器不知道MethodA永远不会被Integer以外的任何东西调用。

答案 1 :(得分:1)

在方法B声明中对所有三个参数使用相同的泛型类型(E)。 您可以使用任何类型的参数(E),但对于所有3个参数必须相同。

尝试添加另一种泛型类型(T):

public class Test {
  public static void main(String[] args) {
    String[] arr = new String[0];
    MethodA(arr);
  }

  public static <E> void MethodA(E[] array) {
    Integer[] intArray = new Integer[0];
    List<E> someList = new ArrayList<E>();
    MethodB(array, intArray, someList);
  }

  public static <E, T> void MethodB(E[] array, T[] secondArray, List<E> list) {
    //Stuff
  }
}

或者,如果有需要,可以添加第三个,以便List不要求E与E []数组中的类型相同。

答案 2 :(得分:0)

MethodB要求所有三个参数都是相同的类型。但是你用E和Integer调用它。试试E [] intArray = null;和编译器不会编译