【发布时间】:2015-07-04 04:11:24
【问题描述】:
我正在阅读有关泛型类型推断的信息,并且此代码是作为无法编译的示例提供的。
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");
}
}
而书中给出的解释是:
"(貌似
StrLastError中的setError()方法覆盖了LastError类中的setError(),然而事实并非如此。在编译的时候,知道了S类型的知识不可用。因此,编译器将这两个方法的签名记录为父类中的setError(String)和子类中的setError(S_extends_CharSequence)——将它们视为重载方法(未覆盖)。在这种情况下,当对setError()的调用是找到,编译器发现两个重载方法都匹配,导致方法调用不明确错误。”
我真的不明白为什么在编译时无法推断类型S。
String 在调用类StrLastError 的构造函数时传递,
从 API 文档中,String 确实实现了接口 CharSequence,
所以这是否意味着S 的<S extends CharSequence> 实际上是String 类型?
我已多次阅读有关泛型主题的 Java 在线教程。我检查了“类型推断”和继承,我只是不知道整个事情是如何工作的。这个问题我真的需要一个解释。
我坚持的观点是:
- 如果子类型不能决定
S,为什么超类型可以决定T,因为超类没有上限?还是因为子类型首先调用超类型的构造函数,所以推断T是String? -
我理解如果构造函数被调用为:
StrLastError<CharSequence> err = newStrLastError<>((CharSequence)"Error");不会有歧义,因为它是简单的方法覆盖。 (或者我在这里错了吗?)
但是,就像我一开始说的,如果String通过了,为什么不能将S推断为String?
【问题讨论】:
-
为什么说它不会产生编译错误??
-
嗨,我说它应该在我的帖子的第一行产生编译错误:)
-
是的,编辑后 ;) 在“代码最终会出现编译错误”之前
-
我没有说它“不”,我说它“应该”,如果我非常确定它产生编译错误的原因,我不会在这里问这个问题.
标签: java