Consider this example (typical in OOP books):
I have an Animal
class, where each Animal
can have many friends.
And subclasses like
Based on the same idea as Super Type Tokens, you could create a typed id to use instead of a string:
public abstract class TypedID {
public final Type type;
public final String id;
protected TypedID(String id) {
this.id = id;
Type superclass = getClass().getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
this.type = ((ParameterizedType) superclass).getActualTypeArguments()[0];
}
}
But I think this may defeat the purpose, since you now need to create new id objects for each string and hold on to them (or reconstruct them with the correct type information).
Mouse jerry = new Mouse();
TypedID spike = new TypedID("spike") {};
TypedID quacker = new TypedID("quacker") {};
jerry.addFriend(spike, new Dog());
jerry.addFriend(quacker, new Duck());
But you can now use the class in the way you originally wanted, without the casts.
jerry.callFriend(spike).bark();
jerry.callFriend(quacker).quack();
This is just hiding the type parameter inside the id, although it does mean you can retrieve the type from the identifier later if you wish.
You'd need to implement the comparison and hashing methods of TypedID too if you want to be able to compare two identical instances of an id.