【问题标题】:"both methods have same erasure" error using bounded type parameters使用有界类型参数的“两种方法都有相同的擦除”错误
【发布时间】:2018-05-29 18:06:27
【问题描述】:

我第一次在 Java 中使用泛型,我遇到了一个我无法克服的问题:为什么会编译:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericCA extends Cc & Aa>
void method(GenericAB myAbobject, GenericCA myCAobject){}

但这不是:

public interface Aa{}
public interface Bb{}
public interface Cc{}


public static <GenericAB extends Aa & Bb>
void method(GenericAB myABobject1, GenericAB myABobject2){}

public static <GenericAB extends Aa & Bb, GenericAC extends Aa & Cc>
void method(GenericAB myAbobject, GenericAC myACobject){}

我得到这个错误:两种方法都有相同的擦除

如果这是一个愚蠢的问题,我很抱歉,但我不明白为什么有界类型参数声明中接口的顺序 似乎 很重要。 实际上,我不认为是导致错误的顺序,但我不明白是什么原因。

我正在阅读this documentation by Oracle,它说我必须将类作为第一个参数,但 Aa、Bb 和 Cc 都是接口。也对不起我的英语。

【问题讨论】:

    标签: java generics type-erasure


    【解决方案1】:

    重要的是顺序 (§4.6):

    类型变量的擦除(第 4.4 节)是其最左边界的擦除。

    GenericBC 擦除为AaCc,具体取决于哪个出现在边界中的第一个(即最左边)。

    另请参阅type erasure tutorialtype erasure, when and what happens Q&A,了解有关类型擦除的一般说明。

    【讨论】:

    • 感谢您的回答!这不是限制吗?或者至少令人困惑?我的意思是,如果我想用泛型重载一个函数(就像我在问题示例中所做的那样),为什么我必须注意顺序?此外,这种机制是否会根据我要绑定的接口数量来限制重载方法的数量(我无法举个例子)?我的意思是,如果 Oracle 这样做当然有充分的理由,但我不明白。顺便说一句,明天我肯定会阅读您发布的链接,我试图快速阅读它们,但它们似乎有点复杂。谢谢!
    • 一般来说,我们不能用泛型做重载,因为“没有两个方法具有相同的擦除”规则。我猜想它不允许的原因与向后兼容性有关(旧的前泛型代码使用新的后泛型代码)。我认为没有其他限制。我认为还有其他一些 JVM 语言确实允许这种重载。
    • 好的,我阅读了这些链接并开始理解,尽管我仍有一些疑问,但我认为与它们合作是习惯它们的最佳方式。顺便说一句,当你说“我们不能用泛型进行重载[...]”时,你的意思是我们不应该还是不可能?我问这个是因为上面的例子有效,而且我用泛型重载了一个方法。谢谢!
    • 禁止两个方法同名和擦除。 (请参阅§8.4.8.3,在第一个粗体部分下,以“这是一个编译时错误...”开头。)例如,void m(List&lt;A&gt; l) {} void m(List&lt;B&gt; l) {} 将是编译器错误,因为这两种方法都会擦除为void m(List l) {}。您问题中的示例(类型变量以不同方式擦除)只是一个相当模糊的特殊情况。
    【解决方案2】:

    因为在类型擦除后的运行时,两个方法都有相同的方法头

    public static <GenericAB extends Aa & Bb> void method(GenericAB myABobject1, GenericAB myABobject2){}
    

    变成

    public static void method(Aa myABobject1, Aa myABobject2){}
    

    public static <GenericAB extends Aa & Bb, GenericBC extends Aa & Cc>void method(GenericAB myAbobject, GenericBC myBCobject){}
    

    变成

    public static void method(Aa myAbobject, Aa myBCobject){}
    

    两种结果方法具有相同的签名,这会导致您的错误

    在 cmet 以下参数固定后编辑

    【讨论】:

    • @Radiodef 谢谢,我已经修复了我的示例。没注意到那个
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-01
    • 2020-04-29
    • 1970-01-01
    • 1970-01-01
    • 2022-01-19
    • 1970-01-01
    相关资源
    最近更新 更多