Using Java generics in an interface to enforce implementation of a method with the implementing type as a parameter
Solution 1
If you just need to handle copyFrom
differently if the DataObject
it's given is the same type as the object itself, just do something like this:
public class DataObjectImpl implements DataObject {
public void copyFrom(final DataObject source) {
if (source instanceof DataObjectImpl) {
...
}
else {
...
}
}
}
On the other hand, you could do it like this, using a different name for the method taking an implementation type. However, I don't see what good this does.
public interface DataObject<T extends DataObject<T>> {
public void copyFrom(DataObject source);
public void copyFromImpl(T source);
}
public class DataObjectImpl implements DataObject<DataObjectImpl> {
public void copyFrom(final DataObject source) { ... }
public void copyFromImpl(final DataObjectImpl source) { ... }
}
Solution 2
You could reduce your code by simply doing:
interface DataObject {
public <T> void copyFrom(T impl);
}
or to be more succinct:
interface DataObject {
public <T extends DataObject> void copyFrom(T impl);
}
You could use this by calling:
o.copyFrom(new DataObjectImpl());
o.<DataObjectImpl> copyFrom(new DataObjectImpl());
Using generics, the implementation of DataObject is always going to be erased at runtime. It seems counter intuitive to know about the implementation because you should be programming to the interface. If I were you, I might look into Data Transfer Objects or cloning.
Like Josh Bloch says, use interfaces only to define types
.
If your type was defined as:
interface DataObject {
byte[] getData();
Long getId();
Timestamp getCreateDtTm();
}
Your impl might contain:
class DataObjectImpl implements DataObject {
// member vars
public DataObjectImpl(DataObject dataObject) {
this.data = dataObject.getData();
this.id = dataObject.getId();
this.createDtTm = dataObject.getCreateDtTm();
}
//getters and setters
}
The implementation or copy strategy wouldn't matter because any implementation abides by the type contract and can be reduced to this clearly defined type.
Comments
-
Ioeth almost 2 years
I have an interface like this:
public interface DataObject { ... public void copyFrom(DataObject source); ... }
And a class that implements it:
public class DataObjectImpl implements DataObject { ... @Override public void copyFrom(final DataObject source) {...} public void copyFrom(final DataObjectImpl source) {...} ... }
Is there any way that I can enforce the implementation of a "public void copyFrom(DataObjectImpl source)" method in the DataObject interface, using generics or otherwise?
-
Ioeth over 13 years"public void copyFrom(T source);" has the same type erasure as "public void copyFrom(DataObject source);". I need the interface to specify both.
-
ColinD over 13 years@loeth: Why do you need that? If you need to handle things differently when the
copyFrom
parameter is aDataObjectImpl
vs. when it's some other implementation ofDataObject
, just use thecopyFrom(DataObject source)
signature and do aninstanceof
check in the implementation. -
Ioeth over 13 yearsI need to do this because currently, all classes implementing the interface do of course specify "public void copyFrom(DataObject source)", but our goal is to move towards the "public void copyFrom(DataObjectImpl source)" methods. However, in the meantime we have hundreds of objects that we don't wish to remove the DataObject method from until the DataObjectImpl method has been specified in the interface for at least one version.