Java generic compiler error: incompatible types

When I did not very fancy things with Java, I found a generalization error that I could not understand why it did not work. The code is:

package test; import java.util.*; public class TestClass { public static class A extends C{} public static class B extends C{} public static class C{} public static class D<T>{} public static class E<T>{} public static void main(String args[]){ E<D<? extends C>> a = new E<D<A>>(); E<D<? extends Object>> b = new E<D<? extends C>>(); E<D<? extends A>> c = new E<D<A>>(); E<D<? super A>> d = new E<D<A>>(); D<? extends C> e = new D<A>(); D<? extends A> f = new D<A>(); D<? extends A> g = new D<A>(); } } 

The error I get when compiling:

  test / TestClass.java: 11: incompatible types
 found: test.TestClass.E <test.TestClass.D <test.TestClass.A >>
 required: test.TestClass.E <test.TestClass.D <?  extends test.TestClass.C >>
       E <D <?  extends C >> a = new E <D <A>> ();
                             ^
 test / TestClass.java: 12: incompatible types
 found: test.TestClass.E <test.TestClass.D <?  extends test.TestClass.C >>
 required: test.TestClass.E <test.TestClass.D <?  extends java.lang.Object >>
       E <D <?  extends Object >> b = new E <D <?  extends C >> ();
                                  ^
 test / TestClass.java: 13: incompatible types
 found: test.TestClass.E <test.TestClass.D <test.TestClass.A >>
 required: test.TestClass.E <test.TestClass.D <?  extends test.TestClass.A >>
       E <D <?  extends A >> c = new E <D <A>> ();
                             ^
 test / TestClass.java: 14: incompatible types
 found: test.TestClass.E <test.TestClass.D <test.TestClass.A >>
 required: test.TestClass.E <test.TestClass.D <?  super test.TestClass.A >>
       E <D <?  super A >> d = new E <D <A>> ();
                           ^
 4 errors

If E<D<? extends C>> E<D<? extends C>> E<D<? extends C>> E<D<? extends C>> found that must necessarily match E<D<? extends Object>> E<D<? extends Object>> E<D<? extends Object>> E<D<? extends Object>> , right? Or am I missing something?

+6
java generics
source share
10 answers

Perhaps this will help you understand:

  ArrayList<Object> aList = new ArrayList<String>(); 

This does not compile with a similar error.

EDIT: Consult: http://www.ibm.com/developerworks/java/library/j-jtp01255.html

+2
source share

This is basically the same case as the previous one. Basically, in the case of generics, you are never allowed to do this:

Think of this example:

 ArrayList<Object> alist = new ArrayList<Number>(); 

This does not compile because it is not a safe type. You can add Strings aList. You are trying to assign a list of objects that are guaranteed to be numbers, but can be any number, into a list that guarantees that you will contain objects, but these can be any objects. If the compiler allowed this case, it would relax the restriction on what types of objects can be listed. This is why you should use a wildcard ?, as such:

 ArrayList<? extends Object> alist = new ArrayList<Number>(); 

To the compiler ArrayList<? extends Object> ArrayList<? extends Object> means "ArrayList of a specific type"? that I don’t know, but which, as I know, extends Object. This ArrayList is guaranteed to contain only elements of this unknown '?' type and therefore only contains objects. "In this case, the compiler, however, will not allow you to do alist.add (2). Why is this because the compiler does not know the type of list items and cannot guarantee that you are allowed to insert into him Integer objects.

Are you right in thinking that D<? extends Object> D<? extends Object> is a supertype of D<? extends C> D<? extends C> . However, List<D<? extends Object>> List<D<? extends Object>> not a subtype of List<D<? extends C>> List<D<? extends C>> , you should use List<? extends D<? extends C>> List<? extends D<? extends C>> List<? extends D<? extends C>> .

Your case is basically equivalent

 ArrayList<D<? extends Object>> alist = new ArrayList<D<? extends C>>(); 

You have the same problem as above, the list on the right side can only contain an object of class D, the type of which is parameter C, and you try to assign it to the list (on the left) it can contain objects of class D, the type parameter of which can be any object .

So, if the compiler assumed that your code would not be type safe, and the following would fail.

 ArrayList<D<? extends Object>> alist = new ArrayList<D<? extends C>>(); //< not type safe alist.add(new D<Number>); //< oops 

In short, what you need for your specific example:

 // type parameter of left hand side is ? extends subtype List<? extends D<? extends Object>> b = Arrays.asList(new D<A>(), new D<B>()); // type parameter of left hand side is identical List<D<? extends C>> b = Arrays.asList(new D<A>(), new D<B>()); // type parameter of left hand side is ? extends subtype List<? extends D<? extends C>> c = Arrays.asList(new D<A>()); // type parameter of left hand side is identical List<D<A>> c = Arrays.asList(new D<A>()); 

Hope this helps.

+2
source share

Check the type of object returned by calling Arrays.asList. I would suggest that it returns List <D <? extends C> an object that cannot be assigned to the list <D <? extends Object>.

+1
source share

<? extends C> <? extends C> indicates the upper bounds of the type, which means that the type must be extended from C. <? extends Object> <? extends Object> apparently more general, so it is incompatible.

Think about this use case. By specifying an upper bound, you expect a certain minimal interface to be implemented. Say you have a doIt() method declared in C. Any class that extends C will have this method, but not every class that extends Object (like every class in Java).

+1
source share

When assigning a variable ( E<T> ) with a non-character common type T assigned object must have exactly T as its common type (including all parameters of the type type T , wildcard and non-character). In your case, T is D<A> , which does not match the type D<? extends C> D<? extends C> .

What can you do because D<A> assigned to D<? extends C> D<? extends C> , wildcard type is used:

 E<? extends D<? extends C>> a = new E<D<A>(); 
+1
source share

This is worse than that. You can't even do this:

 List<D<?>> lDQ = Arrays.asList(new D<A>()); 

More clearly, if you change your program as follows:

 List<D<? extends C>> a = Arrays.asList(new D<A>(), new D<B>()); //compiles List<D<? extends Object>> b = a; //error 

Basically, you declare b as something capable of accepting the general content ( D< anything > ), but the list you assign to it is that it only accepts more specific content ( D< closest common superclass A and B > ).

Declaring b as List<D<? extends Object>> List<D<? extends Object>> means that you could, say, b.add(new D<String>()) , but actually it is List<D<? extends C>> List<D<? extends C>> , so you cannot.

0
source share

The fact is that List<D<? extends Object>> List<D<? extends Object>> basically defines a new class, which means List<D<? extends C>> List<D<? extends C>> . Even when c extends Object, this does not mean that List<D<? extends C>> List<D<? extends C>> extends List<D<? extends Object>> List<D<? extends Object>> and this will be necessary for the configuration command to work.

Althoug this series of articles written for the .NET platform, a description of the problem still persists for Java generics

0
source share

You cannot inherit the generics parameter. Let's say you have the following links:

 List<Object> a; List<String> b; 

Now you assign the same list: a = b;

If any code does the following:

 a.add(new Integer(1)); 

What happens if someone does the following:

 String s = b.get(0); 

You will get an integer from the list of strings. This should not work. That is why List and List are incompatible, although String can be assigned to an object link. Generics do not work with inheritance.

0
source share

I think it will be more clear if we continue your example. We put some functions in E and consider in detail the first line of your main method:

 public static class E<T>{ private final T thing; public void setThing(T thing) { this.thing = thing; } public T getThing() { return thing; } } public static void main(String[] args) { E<D<? extends C>> a1; E<D<A>> a2 = new E<D<A>>(); a1 = a2; // this won't compile, but why? // these things are permissible on a1: a1.setThing(new D<A>()); a2.setThing(new D<B>()); // now let try doing the same thing to a2: a2.setThing(new D<A>()); a2.setThing(new D<B>()); // oops } 

The last line of the new main method is why a1 cannot be set to a2. If the compiler allows you to do this, you can set D <B> to a container that was declared only to hold D <A> s.

The reason why this is not obvious from your original example is because you did not create a separate variable that referenced the object using the more restrictive E <D <A β†’ typing. But, I hope, now you can see that if such a link exists, its type security will be compromised by the destination you tried to make.

0
source share

Nope.
<? extends C> does not match <? extends Object>
If this were so, it would also lead to a (non-stationary) assumption - C extends the object and leads to ...

class C {public void doSomethingMEaningful (); };

List <? extends C> allAtSea = new ArrayList <...> (); List <? extends Object> allObjects = new ArrayList <...> (); allObjects.add (new Integer (88)); ...

allAtSea.addAll (allObjects); ...

allAtSea.get (...). doSomethingMeaningful (...); // Uh-oh .. this finds the Integer 88


The C ++ FAQ provides a clear example for this at 21.3

-one
source share

All Articles