I'm reading about type inference for generics, and this code was provided as an example that fails to compile.
import java.io.*;
class LastError<T> {
private T lastError;
void setError(T t){
lastError = t;
System.out.println("LastError: setError");
}
}
class StrLastError<S extends CharSequence> extends LastError<String>{
public StrLastError(S s) {
}
void setError(S s){
System.out.println("StrLastError: setError");
}
}
class Test {
public static void main(String []args) {
StrLastError<String> err = new StrLastError<String>("Error");
err.setError("Last error");
}
}
And the explanation given in the book was:
"(It looks like the
setError()
method inStrLastError
is overridingsetError()
in theLastError
class. However, it is not the case. At the time of compilation, the knowledge of typeS
is not available. Therefore, the compiler records the signatures of these two methods assetError(String)
in superclass andsetError(S_extends_CharSequence)
in subclass—treating them as overloaded methods (not overridden). In this case, when the call tosetError()
is found, the compiler finds both the overloaded methods matching, resulting in the ambiguous method call error."
I really don't understand why type S
can't be inferred at compile time.
String
is passed when invoking the constructor of class StrLastError
,
and from the API docs, String
does implement interface CharSequence
,
so doesn't that mean that S
for <S extends CharSequence>
actually is of type String
?
I've read the Java online tutorial on the topic of generics several times. I've checked "Type Inference", and Inheritance, I just don't know how the whole thing works. I really need an explanation on this question.
The points I'm stuck at are:
- If the subtype can't decide
S
, how come the super type can decideT
, because the superclass does not have an upper bound? Or does it infer thatT
isString
because the subtype calls the supertype's constructor first? I understand that if the Constructor is invoked as:
StrLastError<CharSequence> err = newStrLastError<>((CharSequence)"Error");
there will be no ambiguity, since it's plain method overriding then. (Or am I even wrong here?)
However, like I said in the beginning, if String
is passed, why can't S
be inferred to be String
?