这是一个正确编译的代码
public enum SupportedConversions {
INTEGER {
@Override
public Integer convert( String ion, Object[] aa) {
return null;
}
},
LONG {
@Override
public Long convert(final String ion, Object[] aa) {
return null;
}
};
public abstract <T> T convert(String val, Object[] aa);
}
但是当我将抽象函数参数更改为对象列表而不是数组时,我得到编译错误,说“方法不会覆盖超类”。只有当返回类型是通用的
时才会发生这种情况示例坏代码
public enum SupportedConversions {
INTEGER {
@Override
public Integer convert( String ion, List<Object> aa) {
return null;
}
},
LONG {
@Override
public Long convert(final String ion, List<Object> aa) {
return null;
}
};
public abstract <T> T convert(String val, List<Object> aa);
}
这是否有理由不起作用。看起来更像是Java中的错误
答案 0 :(得分:1)
问题应该是“为什么第一次编译”而不是“为什么第二次失败”。
两者都坏了。
像
这样的方法签名<T> T convert(String val, Object[] aa)
说“无论调用者是否替换T
,此方法都将返回兼容的结果”。这不是很有用,因为唯一有效的返回值是null
,但至少,编译器会告诉您,当您尝试在以此方式声明的方法中返回不兼容的结果时。
但是子类重写了这个方法,如
Long convert(final String ion, Object[] aa)
换句话说,覆盖一个方法,该方法承诺返回调用者希望的方法,并始终返回Long
。首先应该感觉不对...返回null
时结果仍然兼容,但是当您返回非null
Long
值时结果仍然兼容,编译器甚至不会发出警告关于这一点,因为Long
值与声明的返回类型Long
兼容。
然而,编译器应该发出关于方法声明本身的警告。为了证明问题,使用该声明,您可以编写
String s = SupportedConversions.LONG.convert("bla", null);
并且编译器不会反对。如上所述,基类型声明<T> T convert(…)
承诺返回调用者对T
所采用的任何内容,此处T
被推断为String
。当实现返回Long
实例时,这显然会在运行时中断。
可以编译它的原因是与前Generics代码的兼容性。目的是允许具有不同“泛化”状态的图书馆进行互动。例如。您可以使用最近的jdk编译Java 1.4应用程序代码,即使某些类覆盖了现在的Generic方法。
因此,允许子类中不使用Generics的convert
方法覆盖基类的convert
方法。相比之下,像
Long convert(final String ion, List<Object> aa)
是使用泛型,因此,不允许绕过Generic类型系统。如果您使用原始类型List
,那么您将再次获得一个非泛型声明,该声明可以绕过泛型。
如果你现在想要说,假设前泛化行为在这里是不合逻辑的,那么你并不孤单。不仅因为重写方法在被覆盖的Generic声明的同一编译单元(enum
声明)内,它们都在enum
声明中,这是一个在Java之前不存在的语法结构5(引入泛型的地方)。
此外,重写方法使用协变返回类型,Long
resp。 Integer
,其中方法声明的擦除返回类型为Object
,它也不能出现在Java 5之前的代码中。
但这些(仍然)是规则。您应该关注编译器警告。如果你没有收到警告(我知道Netbeans IDE有默认的麻烦),你应该尝试启用它们。
此代码无法修复。 enum
s无法实现您的目标。您可以删除类型参数T
并让基类型的方法声明返回Object
,但enum
常量中的协变返回类型是无关紧要的,因为它们不是{{1}的一部分API。最好的选择是:
public
RESP。
public interface SupportedConversions<T> {
SupportedConversions<Integer> INTEGER = (String ion, Object[] aa) -> {
return null;
};
SupportedConversions<Long> LONG = (String ion, Object[] aa) -> {
return null;
};
public abstract T convert(String val, Object[] aa);
}