Java泛型、类型推断、继承?

Java泛型、类型推断、继承?,java,Java,我正在阅读泛型的类型推断,而这段代码是作为一个未能编译的示例提供的 import java.io.*; class LastError<T> { private T lastError; void setError(T t){ lastError = t; System.out.println("LastError: setError"); } } class StrLastError<S extends CharSe

我正在阅读泛型的类型推断,而这段代码是作为一个未能编译的示例提供的

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");
    }
}
不会有歧义,因为它是简单的方法重写。(或者我在这里是不是错了?)


但是,正如我在开始时所说,如果传递了
String
,为什么不能将
S
推断为
String

这是一个棘手的示例,要解决它,您需要更改以下行:

class StrLastError<S extends CharSequence> extends LastError<S>
类StrLastError扩展了LastError

您必须提醒自己,这些类是逐个编译的。Java泛型不像其他语言那样是模板。将只有一个编译类,而不是与它一起使用的每个类型都有一个类

通过这种方式,您可以看到类
strlastror
的编译方式需要确保它也可以与实现
CharSequence
为泛型类型S的其他类一起使用

这就是为什么编译器会得到两个不同的方法,而不是一个重写的方法。现在,这将是一个运行时任务,以确保子类可能希望仅在类型建议的情况下重写父类中的方法。由于开发人员很难理解这种行为,并且可能会导致编程错误,因此会引发异常

如果使用CharSequence作为类的泛型类型参数
StrLastError
,则将调用父类中的
setError
方法,因为
“Last Error”
的类型是
String
,它比CharSequence更具体,Java总是选择最具体的方法以防重载。(我希望很明显,在这种情况下,该方法也没有被重写)

如果子类型不能决定S,为什么超类型可以决定t,因为超类没有上界?还是因为子类型首先调用超类型的构造函数而推断T是字符串

超级类型不是决定或推断
t
是什么;通过这个声明,您明确地告诉它什么是
T

class StrLastError<S extends CharSequence> extends LastError<String>
JLS 8.4.8.4。适用于这里

一个类可以继承多个具有 覆盖等效签名(§8.4.2)

如果类C继承了具体的方法,则是编译时错误 其签名是继承的另一个具体方法的子签名 如果一个超类是泛型的,并且它有两个 方法在泛型声明中是不同的,但具有 在特定调用中使用相同的签名。


我理解如果构造函数被调用为StrLastError err=newstrlasterror((CharSequence)“Error”);不会有歧义,因为它的简单方法会覆盖(或者我在这里甚至错了)

不,现在你在胡闹。有趣的是,它会起作用,主要是因为这两种方法的签名已经变成:

void setError(Object s)
void setError(String s)

您希望使用泛型来避免这样的场景;您可能希望在某个时候调用super class方法,但在这种使用这些绑定的场景中,很难实现。

我认为您的修复是正确的,但该示例被认为是故意错误的,OP希望了解其错误原因。您为什么说它不会产生编译错误?您好,我说它应该在我帖子的第一行产生编译错误:)是的,编辑之后;)在“代码应该有编译错误”之前,我没有说“没有”,我说“应该”,如果我非常确定它产生编译错误的原因,我不会在这里问这个问题。谢谢,我想我在第二点中错过了一个,我会修改帖子,但我仍然不明白为什么在main中的声明中显式使用when时,不能在编译时推断S。绑定到子级的泛型类型与绑定到父级的类型不同。如果在泛型方法上有一个类型参数,那么这两种类型也不会相同。如果您对这种行为感到好奇(这里有点超出范围),请鼓励您提出一个新问题。因此编译器首先编译类“LastError”,然后是“StrLastError”,在main的主体中,当调用构造函数时,LastError被显式告知T应该是子类型声明中的字符串,并保留子类类型参数S未确定?否。
S
被约束绑定到
CharSequence
作为上限。这是Java把它搞混的主要原因;
String
是一个
CharSequence
,因此在传递
String
时,超类和子类方法都是有效的。“在编译时,类型S的知识是不可用的。”这是最让我困惑的,所以假设没有超类,类strlastror单独存在,不改变任何其他内容,例如,它的上界,main仍然不变,S仍然不确定?非常感谢,我想我马上就到了。
void setError(CharSequence s)
void setError(String s)
void setError(Object s)
void setError(String s)