Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics - Confusing behavior

Tags:

java

generics

I'm having trouble understanding why I'm getting a compilation error here. Let me share some simple code. The following block of code works fine:

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
  }
}

The problem arises when I add a new generic List parameter to MethodB, calling it from 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
  }
}

Which gives me the following error:

Exception in thread "main" java.lang.Error: Unresolved compilation problem: The method MethodB(E[], E[], List) in the type Test is not applicable for the arguments (E[], Integer[], List)

It seems to be telling me to change the parameter from E[] to Integer[], which is weird because it did not complain about such a thing until after I introduced the List parameter. Again, I feel like I must be making a silly mistake somewhere, but I can't figure it out. Any help would be appreciated! Thanks!

like image 465
Fitzy123 Avatar asked Aug 16 '14 04:08

Fitzy123


1 Answers

In the first example, you're calling MethodB with a String[] and an Integer[].

Since arrays are "covariant" - meaning, for example, you can cast a String[] to an Object[], it calls the version of MethodB with Object for E.

In the second example, it's similar, but you also have a List<E>. Generic classes do not work the same way of arrays - you cannot cast a List<String> to a List<Object>. So it would be invalid for E to be Object (or anything other than whatever E is in MethodA) since then the third parameter couldn't be converted, and it would also be invalid for E to be String since then the first parameter couldn't be converted. So there is no type that works for E.

Note: If you changed String to Integer in main, it still wouldn't compile, even though E could be Integer. That's because the compiler doesn't know that MethodA is never called with anything other than Integer.

like image 197
user253751 Avatar answered Sep 21 '22 22:09

user253751