Jordi
Jordi

Reputation: 23257

Java generics <? super T>: not applicable methods

I've this class:

public abstract class SlightExpression<T> extends Expression<T> {
    public BooleanExpression eq(Expression<? super T> right) {}
}

Go figure the next sentence:

    SlightExpression<?> left;
    SlightExpression<?> right;      
    //...

    left.eq(right);

Java is telling me:

The method eq(capture#19-of ?) in the type SlightExpression<capture#19-of ?> 
is not applicable for the arguments (SlightExpression<capture#20-of ?>)

However,

public abstract class StringExpression extends SlightExpression<String> {}

Then, Java is telling me nothing about it.

StringExpression s, f;
s.eq(f);

I don't understand this behaviour.

Upvotes: 4

Views: 261

Answers (1)

Eran
Eran

Reputation: 393936

When left and right are declared as

SlightExpression<?> left;
SlightExpression<?> right;  

You can assign to them SlightExpressions having different parameter types. For example :

left = new SlightExpression<Integer>();
right = new SlightExpression<String>();

Now, you can't pass a SlightExpression<String> to the eq method of a SlightExpression<Integer> instance.

On the other hand, in your second snippet, both instances are sub-classes of SlightExpression<String>, so there is no problem passing one instance as an argument to the eq method of the other instance.

To better understand the concept, you can apply it to better known classes. For example :

List<?> l1 = new ArrayList <String> ();
List<?> l2 = new ArrayList <Integer> ();
l1.addAll (l2); // this doesn't pass compilation, since you can't add Integer elements to
                // a List<String>

List<?> l1 = new ArrayList <String> ();
List<?> l2 = new ArrayList <String> ();
l1.addAll (l2); // this doesn't pass compilation too, since the compiler doesn't know that
                // l1 and l2 will refer to Lists of the same element type when addAll is 
                // invoked

On the other hand, this snippet will pass compilation, since the compiler sees that both Lists have the same element type :

List<String> l1 = new ArrayList <String> ();
List<String> l2 = new ArrayList <String> ();
l1.addAll (l2);

Upvotes: 3

Related Questions