1

How can i make an interface in java with a function that accepts a parameter of the type that extends the interface?

For example take the interface ISelfComparable

if class A extends it then i would expect it to implement

bool compareTo(A other)

but if class B extends it then i would expect it to implement

bool compareTo(B other)

I know i can use a generic interface but it seems incorrect because it doesn't make any sense for A to extend ISelfComparable<B>

If this is impossible, what is the best practice in this kind of situation?

Plargato
  • 475
  • 3
  • 14

3 Answers3

2

The usual solution is self-bounded generics, as seen in the Enum class.

interface Example<T extends Example<T>> {
    void foo(T t);
}

public class ExampleImpl implements Example<ExampleImpl> {
    @Override
    public void foo(ExampleImpl example) {
    }
}

How it works is a bit dizzying, but is explained very well here for example. There is also a very good answer on the subject here.

Note that it isn't foolproof, as it allows this:

public class ExampleImpl2 extends Example<ExampleImpl {
    @Override
    public void foo(ExampleImpl example) {

    }
}

But in practice the self-bounded idiom is used to express exactly the sort of thing you're after.

If you really, really, really need the parameter object to always be the exact same class as this, you have to do a runtime check. (It also raises the question of why you need this, but that would take us way off topic.)

biziclop
  • 48,926
  • 12
  • 77
  • 104
  • 2
    Mhh, doesn't seem to solve OPs issue. When I create `class ExampleImpl2 implements Example`, then I can change `ExampleImpl` to `class ExampleImpl implements Example` and that's that OP likes to prevent. – Tom Feb 21 '19 at 14:26
  • 1
    @Tom Indeed it doesn't. AFAIK there is no way to express that exact requirement in the Java type system, this is the closest you can get. – biziclop Feb 21 '19 at 14:27
  • 1
    That's what I assume also. OP would need to check the runtime type of the passed `example` object if it exactly matches `this` to be completely sure. – Tom Feb 21 '19 at 14:30
  • The canonical SO thread on this topic is probably [Java Enum definition](https://stackoverflow.com/q/211143/1371329). – jaco0646 Feb 21 '19 at 15:05
0

Have a look at the class java.lang.Comparable: it has an argument with the type of the objects that can be used int compareTo.

By analogy:

public interface ISelfComparable<T extends ISelfComparable<T>> {
    boolean compareTo(T other);
}
Maurice Perry
  • 9,261
  • 2
  • 12
  • 24
  • `Comparable` doesn't has the restriction OP likes to apply. Also see the other answer, it shows that your self-bounded generic doesn't fulfill that requirement either. – Tom Feb 21 '19 at 14:29
0

There is a way to check the type of parameter but only in runtime. For example you can implement type checking in default method:

interface ISelfComparable {
    default boolean compareTo(ISelfComparable param) {
        if (this.getClass() != param.getClass()) {
            throw new IllegalArgumentException();
        }
        ...
    }
}

Then each implementation of this interface should look like this:

class A implements ISelfComparable {
    @Override
    public  boolean compareTo(ISelfComparable param) {
        ISelfComparable.super.compareTo(param);
        ...
    }
}

In this case if you call new A().compareTo(new B()); then java.lang.IllegalArgumentException will be thrown

Ruslan
  • 6,090
  • 1
  • 21
  • 36