我不明白为什么classB不编译:
interface Interface {
<T extends Exception>void method(List<String> list) throws T;
}
// It compile but there is a warning (I understand why)
class ClassA implements Interface {
public void method(List list) throws Exception{}
}
// This class don't compile (I don't get why)
class ClassB implements Interface {
public void method(List<String> list) throws Exception{}
}
ClassB中的编译器错误消息:
ClassB类型的方法method_1(List)具有相同的擦除 作为Interface类型的method_1(List)但不覆盖 它
或许问题是ClassA编译的原因。
为什么&lt;字符串&gt;有所作为?
答案 0 :(得分:4)
让我们首先介绍ClassB
。
方法的类型参数由方法的调用者解析。它不能通过子类中的覆盖来解决。
有两种方法可以使ClassB
起作用。您也可以在那里添加类型参数。 1
class ClassB implements Interface {
public <T extends Exception> void method(List<String> list) throws T{}
}
或者您可以将类型参数移动到接口,因此子类可以决定。
interface Interface<T extends Exception> {
void method(List<String> list) throws T;
}
class ClassB implements Interface<Exception> {
public void method(List<String> list) throws Exception {}
}
至于为什么ClassA
有效,这是因为参数中的原始类型。当您使用原始类型时,所有变为原始类型,这意味着在编译ClassA
时,Interface
看起来像这种原始类型。
interface Interface {
void method(List list) throws Exception;
}
这样做是为了向后兼容。见JLS 4.8 Raw Types :
原始类型的超类(分别是超级接口)是其任何参数化调用的超类(超接口)的擦除。
接着说:
原始类型的使用仅允许作为遗留代码兼容性的让步。 强烈建议不要在将泛型引入Java编程语言后编写的代码中使用原始类型 。未来版本的Java编程语言可能会禁止使用原始类型。
1 我实际上想知道调用者如何解析T
,即编译器如何推断T
是什么,假设什么都没有在方法调用中将指示有效的异常。
根据Eclipse编译器,当您编写以下内容时,T
将被解析为RuntimeException
。
new ClassB().method(null);
您可以通过明确指定类型来覆盖它,例如这将使方法抛出ParseException
。
new ClassB().<ParseException>method(null);
<强>后续强>
Java 8中推断的T
为RuntimeException
。如果没有catch语句,我会在早期版本的Java上遇到以下错误:
1.5.0_22: unreported exception T; must be caught or declared to be thrown
1.6.0_45: unreported exception T; must be caught or declared to be thrown
1.7.0_79: error: unreported exception Exception; must be caught or declared to be thrown
Java 8将整个章节专门用于type inference,它说:
如果绑定集包含
throws
α i ,并且α i 的正确上限最多为Exception
,{ {1}}和Throwable
,然后T i =Object
。