Reputation: 3160
I would like to create a generic interface for those two classes but I'm not sure how to specify the generics the right way.
public class ThingA implements Thing {
public ThingA createCopy(ThingA original);
}
public class ThingB implements Thing {
public ThingB createCopy(ThingB original);
}
I tried it this.
public interface Thing<V extends Thing<V>> {
public V createCopy(V original);
}
But I'm still able to do things like this, which shouldn't be allowed.
public class ThingB implements Thing<ThingA> {
public ThingA createCopy(ThingA original);
}
Upvotes: 7
Views: 992
Reputation: 135
In case you are free to use extension instead of implementation, then you could do that this way:
public interface Thing { ... }
public abstract class Copyable {
public final Copyable copy() {
Copyable clone = createCopy();
if (clone.getClass() != getClass())
throw new RuntimeException("Copy has wrong type!");
return clone;
}
protected abstract Copyable createCopy();
}
And then use it like:
public class Test extends Copyable implements Thing {
public String content = null;
@Override
public Copyable createCopy() {
Test clone = new Test();
clone.content = this.content;
return clone;
}
}
/*code somewhere*/ {
Test t1 = new Test();
t1.content = "Hello world!";
Test t2 = (Test)t1.copy();
System.out.println(t2.content);
}
One problem with this, is that Copyable
is not an interface. However, this can be used without much pain, as seen in the example, but the class checking used is not supported on the language level. With other words, the createCopy
abstract method is not restricted to the class it copies, and all that is up to the programmer who extends the Copyable
class, or a class, which extends it.
The positive side, is that if you call the .copy()
on the object, it must return an object same as itself. Instead of an exception you can return null
, if you want. Then you got good or nothing.
But, to be honest, I don't really understand, why your createCopy
local method has a parameter.
It could be then a static method ... altrough I cannot even imagine what would go into that code block:
static <X extends Thing> X copy(X object) { ... }
May you could combine the pratice with a static generic method and the result becomes a bit more friendly:
public interface Thing extends Cloneable {
public static <X extends Thing> X copy(X thing) {
Object clone = thing.clone();
if (clone.getClass() != getClass())
throw new RuntimeException("Copy has wrong type!");
return (X)clone;
}
}
public class ThingA implements Thing {
public Object clone() { ... }
}
/*code somewhere*/ {
ThingA a1 = new ThingA();
ThingA a2 = Thing.copy(a1);
}
Still, the cloning method is regulated by an exception instead of language restriction, but I think this is far the best solution.
Upvotes: 0
Reputation: 122439
This is not possible. And it is not what Generics is for. Generics is for type safety, i.e. avoiding casts. If someone makes a class ThingB
that implements Thing<ThingA>
somehow, then great. It is perfectly type-safe. Why do you care? How does it impede what you are doing?
Upvotes: 2
Reputation: 5555
There is no this
key-word generics (nor for methods parameters and return values declaration) and thus you cannot do exactly what you want.
In other words the interface will permit to ensure all the methods in the class use consistent types, but not to reference the class type itself.
Upvotes: 6
Reputation: 13672
Are you looking for
public interface Thing<V> {
public V createCopy(V original);
}
? If not, can you explain in more detail what it means to you to "create a generic interface for two classes"?
Upvotes: 0