简体   繁体   中英

Java Generics - Confusing behavior

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!

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 .

In method B declaration You use the same generic type(E) for all three parameters. It meens that you may use a parameter of any kind (E) but it must be the same for all 3 parameters.

Try adding another generic type(T) like this:

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

Or if there is a need you can add third so that List does not require the E to be the same type as in E[] array.

MethodB requires all three parameters be of same type. But you are calling it with E and Integer. Try E[] intArray = null; and compiler will not compalin

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM