Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java generics and inheritance

I have the following abstract classes:

public abstract class AbSuperClass1<K,S> {
    //class definition
}

and:

public abstract class AbSuperClass2<K,S> {
    public abstract <Q extends AbSuperClass1<K,S>> void method(Q arg);
    ...
}

I then have two concrete implementations

public class Concrete1 extends AbSuperClass<String, String>{
    //class definition
}

and:

public class Concrete2 extends AbSuperClass2<String, String>{
    public void method(Concrete1 arg){
        //method definition
    }
}

This will not, however, compile, as Concrete1 is not recognised as a valid type for the argument of method in Concrete2, but as far as I can see Concrete1 is of the correct type, since it extends AbSuperClass1.

Where am I going wrong?

like image 895
Tom Avatar asked Jun 22 '10 17:06

Tom


2 Answers

Consider this program:

public class OtherConcrete extends AbSuperClass<String, String> {}

AbSuperClass2<String, String> x = new Concrete2();
x.method(new OtherConcrete());

What would you expect that to do? You've overridden method in terms of providing an implementation for one specific subtype of AbSuperClass<String, String> - but you haven't provided an implementation which can cope with any AbSuperClass<String, String>, which is what's required.

It's hard to suggest a particular course of action without knowing the details of the situation. Bozho's suggestion of adding another type parameter - allowing you to make the method declaration more specific - is a good one... but the whole thing is becoming very complicated. If you can work out any way to reduce the amount of generic funkiness going on, your code maintainers would probably thank you for it.

like image 104
Jon Skeet Avatar answered Oct 27 '22 02:10

Jon Skeet


Eclipse suggested adding this method:

@Override
public <Q extends AbSuperClass1<String, String>> void method(Q arg) {
    // TODO Auto-generated method stub

}

Another thing you can do, is add this type parameter to the class:

abstract class AbSuperClass2<K,S, Q extends AbSuperClass1<K,S>> {
    public abstract void method(Q arg);
}

and

class Concrete2 extends AbSuperClass2<String, String, Concrete1> {
    public void method(Concrete1 arg) {
        //method definition
    }
}
like image 27
Bozho Avatar answered Oct 27 '22 02:10

Bozho