3
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

}
}

This results in

Name clash: The method setValue(M) of type Foo has the same erasure as setValue(Object) of type JFormattedTextField but does not override it

Why do I get no love from the compiler and how could I fix it?

Torsten
  • 1,172
  • 1
  • 16
  • 37

2 Answers2

3

This is because of type erasure (see this question: Java generics - type erasure - when and what happens)

In a nutshell: The compiler will use String to check that all method calls and type conversions work and then, it will use Object to generate the byte code. Which means you now have two methods with the same signature: public void setValue(Object aValue)

There is no perfect solution for this. You can make the code above compile by using Foo<Object> instead of Foo<String> but that's usually not what you want.

A workaround is to use an adapter:

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

Basically what the adapt() method should do is create a new instance which implements the correct interface and which maps all method invocations to this.

Community
  • 1
  • 1
Aaron Digulla
  • 297,790
  • 101
  • 558
  • 777
  • So the compiler will turn the setValue(String value) in my FooBar-class to setValue(Object value), just because it implements from Foo? And if I didn't implement from Foo it would have let setValue(String value) as is? Since I can have two methods with the same name in one class but with different parameters? – Torsten Aug 24 '12 at 13:01
  • Yes. It knows that `T` is `String` and that means that `setValue(String)` must be the method defined in the interface. It needs to know this so it can properly erase the types when generating the byte code. – Aaron Digulla Aug 24 '12 at 13:27
  • I'm not sure if you understood my question or if I understood your comment's answer. Anyways, I'm going to mark your answer as solution, since it is more detailled than AmitD's. – Torsten Aug 27 '12 at 11:47
  • @Torsten: I'm not meaning to make you completely hopeless but even with 86'000 points on this site, generics can be confusing :-) – Aaron Digulla Aug 27 '12 at 14:55
0

Java uses type erasure for generics. In your case type is String which Subclass of Object also. And your Bar class allows Object so Nameclash happens.

In your scenario because you are using a non generic legacy class with object as parameter in the extended class I will advice you to change method name or change type of Foo to String `Back to 1.4 days :-)

Amit Deshpande
  • 18,407
  • 4
  • 42
  • 69