A friend of mine asked me if I could help him find out the reason behind an error he is getting on a piece of code and most importantly why the error disappears when he add some piece of code. I've looked into the docs about the classes and couldn't find out the reason too.
Here is the code:
import java.util.Arrays;
import java.util.List;
import javax.swing.JComponent;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
public class Test {
public static void main(String[] args) {
/**
* This line shows this compilation error in eclipse:
* Type mismatch: cannot convert from
* List<Class<? extends JComponent&Accessible>>
* to List<Class<? extends JComponent>>
*/
List<Class<? extends JComponent>> listComp = Arrays.asList(JTabbedPane.class,
JPanel.class);
/**
* This one compiles fine and the difference is that
* he added JComponent.class on the list and the
* code is working fine
*/
List<Class<? extends JComponent>> listComp2 = Arrays.asList(JTabbedPane.class,
JPanel.class,
JComponent.class);
}
}
As you can see, the only difference is that on the second list variable we have added the JComponent.class
and the error goes away.
Why is that?
Update
We are using Java JDK 7 update 80
Update 2
Another friend suggested this piece of code and it also works:
List<Class<? extends JComponent>> listComp =
new ArrayList<Class<? extends JComponent>> ( Arrays.asList( JTabbedPane.class,
JPanel.class));
I can duplicate this issue in Java 7, but when I switch to Java 8, the error is no longer given. Also, if I stay in Java 7, but I give a type argument to Arrays.asList
, the error is no longer given.
List<Class<? extends JComponent>> listComp =
Arrays.<Class<? extends JComponent>>asList(JTabbedPane.class, JPanel.class);
Java will attempt to determine the target type of the return of Arrays.asList
. Apparently, both JTabbedPane
and JPanel
extend JComponent
and implement Accessible
. However, JComponent
doesn't implement Accessible
. The result is the most complete, specific type the compiler can get in common from all of the types. For your first example, the inferred type is List<Class<? extends JComponent & Accessible>>
, because both arguments fit that type. When you add JComponent
, the inferred type is now List<Class<? extends JComponent>>
and that matches listComp
, allowing it to compile in Java 7.
Java 8 features improved target type inference. That tutorial's example is of Collections.emptyList
being passed to a method requiring a List<String>
. In Java 7, the inferred type would be List<Object>
and a compilation error would occur. However, in Java 8, the inferred type is List<String>
, matching the method's parameter, and the code compiles.
This isn't quite the same example as your code, but it's close enough that I believe that in general, Java 8's improved target type inference explains why the code compiles with that version.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With