Java Generics - Confusing Behavior

I am having trouble understanding why I am getting a compilation error here. Let me share some simple code. The following code block 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 occurs when I add a new generic List parameter to MethodB by 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 the "main" thread java.lang.Error: Unresolved compilation problem: MethodB method (E [], E [], List) in type Test is not applicable for arguments (E [], Integer [], List)

It seems to me that I need to change the parameter from E [] to Integer [], which is strange because he did not complain about such a thing until he presented the List parameter. Again, I feel that I must be making a stupid mistake, but I can't figure it out. Any help would be appreciated! Thanks!

+5
source share
3 answers

In the first example, you call MethodB with String[] and Integer[] .

Since arrays are "covariant", that is, for example, you can use a String[] for Object[] , it calls the MethodB version with Object for E.

In the second example, this is similar, but you also have a List<E> . Generic classes do not work the same with arrays - you cannot distinguish List<String> from List<Object> . Thus, for E, Object would be invalid (or anything else except that E is in MethodA ), since the third parameter cannot be converted, and it would also be invalid for E to be String , since then the first parameter cannot be converted. Thus, for E there is no type.

Note. If you changed String to Integer in main , it still won’t compile, although E may be Integer . This is because the compiler does not know that MethodA never called by anything other than Integer .

+7
source

In the declaration of method B, you use the same generic type (E) for all three parameters. This means that you can use a parameter of any type (E), but it should be the same for all 3 parameters.

Try adding another generic type (T) as follows:

 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 necessary, you can add a third one so that List does not require that E be of the same type as in the array E [].

+1
source

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

0
source

Source: https://habr.com/ru/post/1200462/


All Articles