Varargs of type Class in Java

If I, for example, have a method that uses varargs for class types that extends the superclass, for example this:

public static <E extends Example> void test(Class<E>... es){} 

Then I try to call this method with two different subclasses of Example, I can only do this if I create an array with two classes in it.

 //this does not work test(E1.class,E2.class); //this does work test(new Class[]{E1.class,E2.class}); public class E1 extends Example {} public class E2 extends Example {} 

Why is this?

+5
source share
2 answers

This line does not compile:

 test(E1.class,E2.class); 

There is only one parameter of type E , and Java must exactly match the expected argument types. It cannot output Example , because the objects are Class<E1> and Class<E2> , not Class<Example> . The invariance of Java generics prevents this.

You can get around this by introducing a wildcard on the upper bound in the test parameter of a general type:

 public static <E extends Example> void test(Class<? extends E>... es) 

This allows Java to infer Example for E by doing a wildcard on the upper bound with E1 and E2 .

The second line creates an unhandled Class es array, bypassing generics and generating an "unchecked call" warning.

 new Class[]{E1.class,E2.class} 

If you try to provide an argument of type Class here, you will get a compiler error with any parameter of a reasonable type halfway:

 // Needs Class<Example> but found Class<E1> and Class<E2> test(new Class<Example>[]{E1.class,E2.class}); // Needs Class<E1> but found Class<E2> test(new Class<E1>[]{E1.class,E2.class}); // Needs Class<E2> but found Class<E1> test(new Class<E2>[]{E1.class,E2.class}); 

Satisfying the output with a wildcard here just reveals the real problem here is creating a shared array.

 // Generic array creation test(new Class<? extends Example>[]{E1.class,E2.class}); 
+6
source

You define a common E of one class that extends the example. You cannot reference two different classes in your call because he will not know what type E is. He expects only one type.

Although this does not work:

 test(E1.class, E2.class); 

It does:

 test(E1.class, E1.class); 

The reason you can do this with an array is due to type erasure. The compiler does not see that the classes inside the array are different.

If you change your method to accept any class that extends Example , it will work.

 public static void test(Class<? extends Example>...classes) 
+2
source

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


All Articles