Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java Abstract Class Implementing an Interface with Generics

I am trying to define an abstract class implementing Comparable. When I define the class with following definition:

public abstract class MyClass implements Comparable <MyClass> 

subclasses have to implement compareTo(MyClass object). Instead, I want every subclass to implement compareTo(SubClass object), accepting an object of its own type. When I try to define the abstract class with something like:

public abstract class MyClass implements Comparable <? extends MyClass> 

It complains that "A supertype may not specify any wildcard."

Is there a solution?

like image 883
Cem Avatar asked Aug 28 '10 23:08

Cem


People also ask

Can an abstract class implement an interface in Java?

Java Abstract class can implement interfaces without even providing the implementation of interface methods. Java Abstract class is used to provide common method implementation to all the subclasses or to provide default implementation. We can run abstract class in java like any other class if it has main() method.

Can abstract class have generic?

Luckily, we can use Java Generics. We can first declare an abstract class that uses generics T . Our generic T could refer to any class (i.e. String , Double , Integer , etc.). This is declared when the AbstractJob class is referenced.

Can a generic class implement an interface?

Only generic classes can implement generic interfaces. Normal classes can't implement generic interfaces.


2 Answers

It's a little too verbose in my opinion, but works:

public abstract class MyClass<T extends MyClass<T>> implements Comparable<T> {  }  public class SubClass extends MyClass<SubClass> {      @Override     public int compareTo(SubClass o) {         // TODO Auto-generated method stub         return 0;     }  } 
like image 59
whiskeysierra Avatar answered Sep 19 '22 17:09

whiskeysierra


Apart from the mechanical difficulties you're encountering declaring the signatures, the goal doesn't make much sense. You're trying to establish a covariant comparison function, which breaks the whole idea of establishing an interface that derived classes can tailor.

If you define some subclass SubClass such that its instances can only be compared to other SubClass instances, then how does SubClass satisfy the contract defined by MyClass? Recall that MyClass is saying that it and any types derived from it can be compared against other MyClass instances. You're trying to make that not true for SubClass, which means that SubClass does not satisfy MyClass's contract: You cannot substitute SubClass for MyClass, because SubClass's requirements are stricter.

This problem centers on covariance and contravariance, and how they allow function signatures to change through type derivation. You can relax a requirement on an argument's type—accepting a wider type than the supertype's signature demands—and you can strengthen a requirement on a return type—promising to return a narrower type than the supertype's signature. Each of these freedoms still allows perfect substitution of the derived type for the supertype; a caller can't tell the difference when using the derived type through the supertype's interface, but a caller using the derived type concretely can take advantage of these freedoms.

Willi's answer teaches something about generic declarations, but I urge you to reconsider your goal before accepting the technique at the expense of semantics.

like image 37
seh Avatar answered Sep 22 '22 17:09

seh