类型擦除、重写和泛型

2022-09-01 06:05:57

有人可以向我解释为什么

@Override
public void fooMethod(Class<?> c)

不覆盖

public void fooMethod(Class c)

并给我以下错误:

 - Name clash: The method fooMethod(Class<?>) 
of type SubClass has the same erasure as fooMethod(Class) of 
type SuperClass but  does not override it

 - The method fooMethod(Class<?>) of type 
SubClass must override a superclass method

?

编辑:“”表示 Java(TM) 2 Runtime Environment, Standard Edition (build 1.5.0_16-b06-284)。至于代码片段,它已经在上面了,差不多;以上扩展了下面的一个。java -version


答案 1

的签名与擦除后的签名相同,因为擦除只是 (JLS 4.6)。因此,是 的子签名,但不是相反的 (JLS 8.4.2)。fooMethod(Class<?>)fooMethod(Class)Class<?>ClassfooMethod(Class)fooMethod(Class<?>)

要使用实例方法重写,您需要重写方法成为重写方法 (JLS 8.4.8.1) 的子签名。这里的情况显然并非如此。

现在我们已经确定了子类方法不会根据 JLS 覆盖超类方法的事实,让我们看一下发生类型擦除时的运行时影响。我们现在有两个看起来完全“相同”(相同的名称,相同的参数类型)但不会相互覆盖的方法。如果它们不重写,则它们必须在子类型上作为单独的方法同时可用,但它们具有相同的运行时签名:冲突。所以Java必须禁止它。

允许使用原始参数类型覆盖泛型参数类型,因为原始类型的存在正是出于这个原因:它们是一种方便的机制,具有特定的不健全类型规则,以适应与旧代码的交互。因此,这里的类型系统将决定子类方法确实覆盖了超类方法,它们在类型擦除后相同的,我们永远不会有冲突。因此,可以独立于现有的非泛型代码生成库。


答案 2

因为比仅仅更具体。Class<?>Class

例如,无法覆盖 。我忘记了这个术语,但是具有泛型的类型将始终与没有泛型的类型不同。foo(Class<List>)foo(Class<Collection>)


推荐