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?
Any class that inherits a parent class, or implements an interface is a "Polymorph" of the parent class / interface. i.e., wherever you need an interface instance, your polymorphic version (or polymorph) can fit in well.
To declare a class that implements an interface, you include an implements clause in the class declaration. Your class can implement more than one interface, so the implements keyword is followed by a comma-separated list of the interfaces implemented by the class.
You mean that you just want to see in the IDE which classes implement an interface? Put the cursor on the name of the interface and press F4 (Open Type Hierarchy). That will open a window that shows a tree with all classes that Eclipse can find that implement the interface.
Yes, you can. If you implement an interface and provide body to its methods from a class. You can hold object of the that class using the reference variable of the interface i.e. cast an object reference to an interface reference.
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
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)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With