20

I came to a problem with interfaces in a program I'm making. I want to create a interface which have one of its methods receiving/returning a reference to the type of the own object. It was something like:

public interface I {
    ? getSelf();
}

public class A implements I {
    A getSelf() {
        return this;
    }
}

public class B implements I {
    B getSelf() {
        return this;
    }
}

I can't use an "I" where it's a "?", because I don't want to return a reference to the interface, but the class. I searched and found that there are no way to "self-refer" in Java, so I can't just substitute that "?" in the example for a "self" keyword or something like this. Actually, I came up to a solution that goes like

public interface I<SELF> {
    SELF getSelf();
}

public class A implements I<A> {
    A getSelf() {
        return this;
    }
}

public class B implements I<B> {
    B getSelf() {
        return this;
    }
}

But it really seems like a workaround or something alike. Is there another way to do so?

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Leonardo Raele
  • 2,400
  • 2
  • 28
  • 32
  • I don't feel the workaround - your solution seems like precisely what I _think_ you want, and better than the offered answers. Can you explain how it feels "off"? – Ed Staub Nov 17 '11 at 03:54
  • 1
    Yes, the solution I bring really solve the problem, but ONLY if everyone who implements I use it's own class as generic type of I. I do not feel it's right, becouse if someone do not follow this rule, the code will broke. For example, a "class C implements I" won't work; everyone who wants to create an implementation of I should be aware of this, I do not think this is rigth. That is my line of thought. – Leonardo Raele Nov 17 '11 at 04:28
  • 1
    This doesn't make sense to me. The whole point of an interface is to assign a type to a group of classes that implement a common set of methods so that they can be used interchangeably. I see two problems with what you are asking. First, if each class that implemented the method returned a different type then the methods would not in fact have common methods. If you could get away with it, then you would not be able to use the classes interchangeably: `I x; A = x.getSelf(); // only works for A objects B = x.getSelf(); // only works for B objects` – Paul Jackson Nov 17 '11 at 14:16
  • 1
    @PaulJackson, this would be useful if, for example, you have a vector interface with perhaps two implementations, a color and a (3D) point. Then a generic method could work with their add and multiply methods which return a color and a point respectively without being bothered by the details of the addition. – jgon May 29 '13 at 00:08

4 Answers4

13

There is a way to enforce using ones own class as a parameter when extending an interface:

interface I<SELF extends I<SELF>> {
    SELF getSelf();
}

class A implements I<A> {
    A getSelf() {
        return this;
    }
}

class B implements I<A> { // illegal: Bound mismatch
    A getSelf() {
        return this;
    }
}

This even works when writing generic classes. Only drawback: one has to cast this to SELF.

As Andrey Makarov noted in a comment below this does not work reliably when writing generic classes.

class A<SELF extends A<SELF>> {
    SELF getSelf() {
        return (SELF)this;
    }
}
class C extends A<B> {} // Does not fail.

// C myC = new C();
// B myB = myC.getSelf(); // <-- ClassCastException
Community
  • 1
  • 1
Patrick Böker
  • 3,173
  • 1
  • 18
  • 24
  • 3
    Here cast to `SELF` is unsafe. Consider the following: `class B extends A {}` and then `class C extends A {}`. All type restrictions are met but in `C` the `getSelf()` method will have `B` as return type, while `C` does not extend `B` and therefore casting will produce `ClassCastException`. – Andrey Makarov Mar 30 '17 at 07:01
7

Java supports covariant return types, so that's one option. Take advantage of the fact that both A and B are derived from Object:

public interface I {
    Object getSelf();  // or I, see below
}
public class A implements I {
    A getSelf() { return this; }
}
public class B implements I {
    B getSelf() { return this; }
}

The point is that both A.getSelf() and B.getSelf() are legitimate overrides of I.getSelf(), even though their return type is different. That's because every A can be treated like an Object, and so the return type is compatible with that of the base function. (This is called "covariance".)

In fact, since A and B are also known to derive from I, you can replace Object by I for the same reasons.

Covariance is generally a Good Thing: Someone who has an interface object of type I can call getSelf() and get another interface, and that's all she needs to know. On the other hand, someone who already knows he has an A object can call getSelf() and will actually get another A object back. The additional information can be used to get a more specific derived type, but someone who lacks that information still gets everything that's prescribed by the interface base class:

I x = new A();
A y = new A();

I a = x.foo();    // generic
A b = y.foo();    // we have more information, but b also "is-an" I
A c = (A)x.foo(); // "cheating" (we know the actual type)
Kerrek SB
  • 464,522
  • 92
  • 875
  • 1,084
  • I think this is the solution I was looking for. Although this does not seems better or clearer to me than using templates, this is an alternative. Thanks! – Leonardo Raele Nov 17 '11 at 04:38
  • 2
    @LeonardoRaele - it is exactly the solution that you dismissed when you said *"I cann't use an 'I'"* :-) – Stephen C Nov 17 '11 at 05:57
  • @StephenC: Indeed - this isn't as much a "solution" as it is an explanation of why your initial idea is correct: The language was designed with this behaviour in mind! – Kerrek SB Nov 17 '11 at 13:30
  • @StephenC Of course this is; but it's best for what I was looking for. My question was if there was any better way to do so. The answer I got was "no". – Leonardo Raele Nov 23 '11 at 14:16
3

I was wondering if there are any other way to do so?

You can write it as follows:

public interface I {
   I getSelf();
}

and then cast the result to the type you want. Your existing A and B classes will work as-is.

(This is an example of return type covariance. Support for return type covariance was added in Java 5. This approach will give compilation errors in older JDKs.)

The alternative version (you call it a work-around, but it isn't really) that uses generics allows you to avoid the explicit typecast. However, there is an implicit typecast in the generated code, and at runtime ... unless the JIT compiler can optimize it away.

There are no better alternatives, AFAIK.

Stephen C
  • 698,415
  • 94
  • 811
  • 1,216
1

As others have said, you can override the return type in the implementing classes:

public interface I {
    public I getSelf();
}

public class A implements I {
    @Override
    public A getSelf() {
        return this;
    }
}

However, I have two 'why' questions for you:

1: Why do you want an Interface to return the implementing object? It seems to run against the general ideas of interfaces and inheritance to me. Can you show an example of how this might be used?

2: In any case, why would you want this function? If a.getSelf() == a, why not just use a?

Trasvi
  • 1,207
  • 1
  • 15
  • 23
  • 1. I'm developing a game for an academic project; I'm in the Board class which should manage the object that are in the board. Since I want the Board(lie, my teacher wants it =P) to be as generic as possible(to allow the Board to be used in another games, for example), I'm working with a custom interface Piece. I want to create a method "Piece onColision(Piece p)", the piece compares itself to another and returns the remaining one(p or this). 2. This method is purely hypotetic, there's no real implementation to it. – Leonardo Raele Nov 17 '11 at 04:05
  • In that case, I would still return the interface type. When two pieces collide you're only interested that a piece is returned. If necessary, you can access the type later by way of o.getClass(). In a response above, you talk about the fact that A a = x.getSelf() cannot always be used. That is the exact reason why what you are trying to implement isn't really supported: there is no real way to use it without lots of type casting, which would seem to make your program *less* generic rather than more. – Trasvi Nov 17 '11 at 04:22
  • This is true for the return type, but I was curious about the receiving parameter. The class which implements Piece should receive an reference to an object of it's own class, that way thay can compare thenselves using specif fields of that class. Example: ChessPiece should compare itself to another different from how TableRPGPiece does. – Leonardo Raele Nov 17 '11 at 04:49