Java is not like C. There isn't 'one variant of the Box class for every imaginable T / every T that is actually used in the code base'. There's just Box. For example:
new Box<String>().getClass() == new Box<Integer>().getClass() // this is true
You will not have a separate class loaded, etc.
This does have some side effects: It is IMPOSSIBLE to derive String
from the variable x in: Box<?> x = new Box<String>();
- that information is now gone. This is called erasure.
Effectively, generics are almost entirely a figment of the compiler's imagination. It's like typing info in typescript and such: It is there at compile time and the compiler will use it to for example tell you that types don't line up (compiler errors), but once the compiler accepts it all, it gets compiled into a form such that, at runtime, this information is simply eliminated entirely*.
This is why the above code works without complaint: You have a static method, the <T>
doesn't even exist here.
Let's zoom in on your get and set methods and the 't' field: They are exactly is if they read: private Object t; public void set(Object o) { this.t = t; } public Object get() { return t; }
with only one exception: If, at compile time, it doesn't make sense, the compiler will refuse to compile it. Furthermore, for any callers to the get
call, a cast is silently included.
*) Not quite entirely; any usage of generics in signatures, so, the types of fields, your class's own definition, and your implements
and extends
lines, and in the return types or parameter types of your methods, is not eliminated, but it is as if it is a comment to the VM: The VM does not care about this stuff; it exists solely so that, if you are invoking javac
with some stuff on the classpath, that javac knows what the generics are when interacting with these members. That is all.