|
I don't often find myself needing to get T, but sometimes I do. Consider the case of a Handler<T extends Foo> interface that several classes implement. If I have several of these, for various Foo subtypes, I might want to put them in some sort of collection that I can look into later after receiving a Foo message, so that I can dispatch it appropriately. Why do I have to do this dispatch myself? The types of all the Handlers go away, so I need to hold on to them somehow, and match at runtime. The clear way to do this is to put them in a Map<Class<T>, Handler<T>>. Now how do these Handler objects declare that they're ONLY able to handle a specific Foo subtype (let's call it FooBar)? It'd be REALLY nice if I could just say "Hey handler, what's your generic type? Is the message I just got an instanceof your generic type?" Java won't let you do this due to erasure. Okay we can get around this. Each Handler<T> has to declare a method (say getType()) that returns the Class<T>. Since I'm generically declaring my class FooBarHandler<FooBar>, I can protect myself from returning a BazBat in this method, but there's NO way for me to abstract this method away. Each Handler has to declare a "public Class<T> getType()" that returns T.class. But since T isn't a thing past compile time, I have to repeat this same method implementation for each concrete type. Gross. This has the added irritation of forcing all the parent classes, if they implement this interface, to be abstract, since they can't implement the method appropriately. This isn't necessarily a bad thing, but the limitation is annoying. In an ideal world, I can declare some ParentHandler<T> that has this method, and have all my handlers just extend it, with no duplication. |
No, it wouldn't be nice, it would be unsafe. If one day you end up adding a new type in your container, you need to update your runtime check as well or your code will fail in mysterious ways.
Erasure keeps you honest by asking you to think carefull about the types so that they can be checked by the compiler, and once the compiler has done this verification, you are guaranteed that your code will work.
Any language feature that encourages the use of reflection , such as reification of types, should not be supported by a language that wants to claim to be sound.