使用相同的方法名实现接口和抽象类,从而导致通用名称冲突

时间:2012-08-24 12:40:40

标签: java generics interface name-clash

public interface Foo <T> {
   void setValue(T value);
}

public abstract class Bar extends JFormattedTextField{
    @Override
    public void setValue(Object value) {

    }
}

public class FooBar extends Bar implements Foo<String>{
    @Override //Foo
    public void setValue(String aValue) {
    // TODO Auto-generated method stub

    }

    @Override //Bar
    public void setValue(Object aValue) {
    // TODO Auto-generated method stub

}
}

这导致

  

名称冲突:Foo类型的方法setValue(M)具有相同的名称   擦除为JFormattedTextField类型的setValue(Object)但不是   覆盖它

为什么我不喜欢编译器,我该如何解决?

2 个答案:

答案 0 :(得分:3)

这是因为类型擦除(请参阅此问题:Java generics - type erasure - when and what happens

简而言之:编译器将使用String检查所有方法调用和类型转换是否有效,然后,它将使用Object生成字节代码。这意味着您现在有两个具有相同签名的方法:public void setValue(Object aValue)

没有完美的解决方案。你可以使用Foo<Object>而不是Foo<String>来编译上面的代码,但这通常不是你想要的。

解决方法是使用适配器:

public class FooBar extends Bar {
    public Foo<String> adapt() {
        return new Foo<String>() {
            public void setValue(String value) {
                FooBar.this.setValue( value );
            }
        }
    }
}

基本上adapt()方法应该做的是创建一个实现正确接口的新实例,并将所有方法调用映射到this

答案 1 :(得分:0)

Java使用类型擦除来表示泛型。在你的情况下,类型是String,它也是Object的子类。而你的Bar类允许对象,因此Nameclash会发生。

在您的场景中,因为您在扩展类中使用了带有object作为参数的非泛型遗留类,我将建议您更改方法名称或将Foo的类型更改为String`返回1.4天:-)