Reputation: 23257
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
Reputation: 393936
When left and right are declared as
SlightExpression<?> left;
SlightExpression<?> right;
You can assign to them SlightExpression
s 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