Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Generics name clash, method not correctly overridden

Tags:

java

generics

I have seen different questions regarding this, but I still find this topic to be very confusing.

All I want to do, is have an abstract class that implements an interface, and have a class extending this abstract class so that the hard class needs to implement getKommune() and setKommune(Kommune kommune), but not the other method, because that is in the abstract class.

I have the following interface.

public interface KommuneFilter {

    <E extends AbstractKommune<?>> void addKommuneFromCurrentUser(E e);

    Kommune getKommune();

    void setKommune(Kommune kommune);
}

And this Abstract class

public abstract class AbstractKommune<E extends AbstractKommune<?>> implements KommuneFilter {
    @PrePersist
    void addKommuneFromCurrentUser(E e) {
            Kommune k = e.getKommune();
    }
}

And I want to use it like this

    public class Person extends AbstractKommune<Person> {
        private Kommune kommune;             
        public void setKommune(Kommune kommune) {this.kommune=kommune;}
        public Kommune getKommune() {return kommune;}
    }

However, I get

Name clash: The method of has the same erasure of type but does not override it

Why isn't it correctly overridden?

UPDATE

Thanks to @Bozho, the solution is this:

public interface KommuneFilter<E extends AbstractKommune<?>> {
    public void addKommuneFromCurrentUser(E e);
}

public abstract class AbstractKommune<E extends AbstractKommune<?>> implements KommuneFilter<E> 

public class Person extends AbstractKommune<Person>
like image 214
Shervin Asgari Avatar asked Mar 30 '10 09:03

Shervin Asgari


People also ask

Does a generic method have to be static?

Static and non-static generic methods are allowed, as well as generic class constructors. The syntax for a generic method includes a list of type parameters, inside angle brackets, which appears before the method's return type.

What is name clashing in Java?

At runtime, the parameter types are replaced by Object . So saveAll(Collection<?>) and saveAll(Collection<MyClass>) are transformed to saveAll(Collection) . This is a name clash.


2 Answers

I'd suggest making the interface generic, rather than only its method:

interface KommuneFilter<E extends AbstractKommune<?>> { .. }

And then

public abstract class AbstractKommune<E extends AbstractKommune<?>> 
     implements KommuneFilter<E> 
like image 191
Bozho Avatar answered Oct 29 '22 13:10

Bozho


The reason why it's a name clash and not an override is because it isn't. The method specified by the interface is a generic method; your abstract class's attempt to override it isn't.

A more concise code that reproduces your problem is this:

interface I {
    <E> void foo(E e);
}

class C<E> implements I {
    public void foo(E e) { // name clash at compile time!
    }
}

The problem here is that interface I specifies that implementors must provide a generic method <E>foo (it can be an <Integer>foo, <Boolean>foo, etc), but say, a C<String> really only has foo(String).

One way to fix this is to make C.foo a generic method, to properly @Override the generic method of interface I:

interface I {
    <E> void foo(E e);
}

class C<E> implements I {
    @Override public <T> void foo(T t) {
    }

    public static void main(String args[]) {
        C<String> o = new C<String>();
        o.<Integer>foo(0);
        o.<Boolean>foo(false);
    }
}

You can see what this does in the above code: you have a generic type C<E> with a generic method <T>foo (you can use E instead of T, but that wouldn't change anything -- it's still a generic method with its own type parameter).

Now a C<String> also has <Integer>foo, etc, as specified by interface I.

If this isn't something that you need, then you probably want to make interface I<E> generic instead:

interface I<E> {
    void foo(E e);
}

class C<E> implements I<E> {
    @Override public void foo(E e) {
    }
}

Now the type and the method shares the same type parameter (e.g. an I<Boolean> only has a foo(Boolean), a C<String> only has a foo(String)) which is likely what you had originally intended.

like image 43
polygenelubricants Avatar answered Oct 29 '22 13:10

polygenelubricants