0

I have an interface with a function that currently returns itself. However, I would like any implementation classes to instead return that class instead of the base interface. For example, in this simplified example, this works fine:

public interface MyInterface<T, U> {
    public void foo(T t, U u);

    public MyInterface baz();
}

public class MyClass<T, U> implements MyInterface<T, U> {
    @Override
    public void foo(T t, U u) {}

    public MyClass bar() {
        return this;
    }

    @Override
    public MyInterface baz() {
        return this;
    }
}

But if I were to change the last function to this:

@Override
public MyClass baz() {
    return this;
}

This fails, obviously, because the overriding function no longer matches the declaration in the interface.

The reason I need baz() to return Class instead of Interface is because the caller may call bar and baz an arbitrary number of times in an arbitrary order, but currently all bar() calls must be before all baz() calls, unless we repetitively downcast it.

What complicates this even more is the foo() function which uses two generic types. I looked into using curiously recurring generic patterns but was not able to find a reasonable solution because Interface already deals with generics, even without it.

Is there any way around this problem? Thanks!

mapo
  • 1
  • 1
  • Why do you think the overridden `baz()` can't return `Class`? Did you try? – shmosel Aug 12 '19 at 23:12
  • 1
    Why are you returning raw forms of your interface and class? Also, Java has return type covariance; you can override `baz` to return a `Class`, or a `Class` once the rawness has been eliminated. (I know it's just an example, but it's a poor choice of class name due to the existing `java.lang.Class` class.) – rgettman Aug 12 '19 at 23:12
  • 1
    Possible duplicate of [Is there a way to refer to the current type with a type variable?](https://stackoverflow.com/questions/7354740/is-there-a-way-to-refer-to-the-current-type-with-a-type-variable) – Tom Aug 12 '19 at 23:13
  • Possible duplicates: [Builder Pattern and Inheritance](https://stackoverflow.com/questions/21086417/builder-pattern-and-inheritance) and [Subclassing a Java Builder class](https://stackoverflow.com/questions/17164375/subclassing-a-java-builder-class). – rgettman Aug 12 '19 at 23:15
  • My apologies @shmosel. I thought that the reason my code was failing with return type ```Class``` was because of overloading problems. The actual reason is because in my actual implementation, the ```baz()``` function is implemented in an abstract class between ```Interface``` and ```Class```, so even if it were to return ```AbstractClass```, this would not be enough of a downcast for ```Class``` to use. Thank you for the suggestion @rgettman, the reason I have not used return type covariance is because it is not an easily extensible solution for multiple inheriting layers of concrete classes – mapo Aug 12 '19 at 23:34

1 Answers1

1

If you want the interface to return an defined type, then you need another type parameter (e.g. named W), and you'd want to make sure that type is an Interface, so:

public interface MyInterface<T, U, W extends MyInterface<T, U, W>> {
    public void foo(T t, U u);

    public W baz();
}

public class MyClass<T, U> implements MyInterface<T, U, MyClass<T, U>> {
    @Override
    public void foo(T t, U u) {}

    public MyClass<T, U> bar() {
        return this;
    }

    @Override
    public MyClass<T, U> baz() {
        return this;
    }
}

Note: Added prefix My to avoid confusion with built-in class named Class.

Andreas
  • 154,647
  • 11
  • 152
  • 247