methods accessiblity restrictions
I am confused about some examples from Angelica Langer FAQ regarding method accessiblity.
class Box<T>{
private T t;
...
publicint compareTo(Comparable<?super T> other)
{
return other.compareTo(t);
}
public Box<?super T> copy()
{
returnnew Box<T>(t);
}
}
publicvoid test1()
{
Box<?extends Number> unknownBox = numberBox;
Box<?super Number> box3 = unknownBox.copy();// error
}
Why "Box<? super Number> box3 = unknownBox.copy); // error" fails compilation? I mean if you think about it, " super capture of ? extends Number" means "supertype of Number", so it should be legal to pass unknownBox.copy() to Box<? superNumber>, right? After all, we can do:
Box<?super Number> box=new Box<Number>();
Box<?super Number> box2=new Box<Object>();
However if unknownBox is declared Box<? super Number>, then comiler reacts differently:
publicvoid test2()
{
Box<?super Number> unknownBox = numberBox;
Box<?super Number> box3 = unknownBox.copy();// ok
}
What's going on?
> Why "Box<? super Number> box3 = unknownBox.copy); //
> error" fails compilation? I mean if you think about
> it, " super capture of ? extends Number" means
> "supertype of Number", so it should be legal to pass
> unknownBox.copy() to Box<? superNumber>, right?
Why should it? Think about it using the following hierarchy:
PostiveInteger extends PositiveNumber extends Number
It's not the same thing with
Postive<Integer> extends Positive<Number> extends Number
the target type is Box<? super Number>
which is a supertype of Box<Number>
or Box<Object>
It's not the same thing with
Postive<Integer> extends Positive<Number> extends Number
the target type is Box<? super Number>
which is a supertype of Box<Number>
or Box<Object>
Huh? Maybe my reply was too short?
Thinking about it, my suggestion is not even necessary:Box<? extends Number> unknownBox = new Box<Integer>();
Box<? super Number> box3 = unknownBox.copy(); // error
The copy call will return a Box<Integer> which is a Box<? super Integer> but no Box<? super Number>.
I got your point. But still, I want to ask, how can I intuitively deduce what's legal and what's illegal from the compiler's point view? I don't want to see the error message the comiler produces, and try my best to think a bad example to make sense of it. It's hard.
For instance,
Box<Integer> integerBox=new Box<Integer>(44);
Box<? extends Number> unknownBox = integerBox;
Comparable<Object> comparableToObject =...;
Comparable<? super Number> comparableToNumber = comparableToObject;
Comparable<? super Integer> comparableToInteger=new Integer(1);
unknownBox.compareTo(comparableToNumber); // ok
unknownBox.compareTo( comparableToInteger ); //error
How do u make sense of the last two statements:
unknownBox.compareTo(comparableToNumber); // ok
unknownBox.compareTo( comparableToInteger ); //error
How many people have the same feeling as i have that in theory generic is a very good idea but in reality it does a good job of confusing developers, especially with those mysterious capture-of ? error messages? Everywhere i look for a answer, invetiablly the answer pattern is "well, you can't do this, suppose you have a ...then...., see, do u get it?". But come on, what we really want is to understand how it works, not first see the result (the error message), then try to come up with a bad example to justify the result.
Angelika Langer dispels some clouds, but I feel her language is somewhat convoluted. Maybe it's just me because English is not my first language.
> How do u make sense of the last two statements:
>
> unknownBox.compareTo(comparableToNumber); //
> ok
> unknownBox.compareTo( comparableToInteger );
> //error
Well, you could try with thinking about it (no offense meant).
Your Box defines to take a Comparable<? super T> as parameter, where T of unknownBox is Number. comparableToInteger does have Integer als lower bound. And as Integer is neither Number nor a superclass of Number, it fails.
There is no mystery here.
> Well, you could try with thinking about it (no
> offense meant).
No offense taken. What I mean is that when I write a library, I can't possibly foresee how my clients will use it, so i don't know what their problem is, hence I don't know if i use generics right: do i make the parameter too restricted or too loose? etc.
> Your Box defines to take a Comparable<? super T> as
> parameter, where T of unknownBox is Number.
I don't think that's precise here, in this case the method takes an argument of:
<? super (capture-of ? extends Number)>
so the T here is:
capture-of ? extends Number
> No offense taken. What I mean is that when I write a
> library, I can't possibly foresee how my clients will
> use it, so i don't know what their problem is, hence
> I don't know if i use generics right: do i make the
> parameter too restricted or too loose? etc.
Well, of course. A library can only be implemented to what it can handle. but that is no problem with Generics but the knowledge on requirements for the library.
> I don't think that's precise here, in this case the
> method takes an argument of:
> <? super (capture-of ? extends Number)>
> so the T here is:
> capture-of ? extends Number
There is no need to be too precise here. The capture-of only signals, that you have a concrete type at this point in code, but you only know about its upper bound, which is Number. Hence the lower bound will still resolve to Number. At least, the compiler does not know better.
> Well, of course. A library can only be implemented to
> what it can handle. but that is no problem with
> Generics but the knowledge on requirements for the
> library.
to give u an example, please look at another thread I posted, "Callable interface", i think my usage is perfectly sensible, yet the Executor is too restricted in its method parameter defintion. So it's not all about requirements.
Thank you.