That's precisely how the JVM behave, which aggravates a lot of people when writing code using generics. In C# I can do the following:
public T getInstance<T>() {
return this.Instances[typeof(T)];
}
Or, even better:
public T createInstance<T>() {
return new T();
}
Meanwhile Java requires this:
public <T> T getInstance(Class<T> cls) {
return this.instances[cls];
}
The type information above (the generic parameter T) is stripped after compilation, so the Class parameter is needed on the method to get a solid reference to the type we need to work with at run-time. This gets worse when we want to do the second example.
public <T> T createInstance(Class<T> cls) {
return cls.newInstance();
}
It gets even more fun when you throw in non-default constructors. Non-reified generics are a giant pain in the butt.
There are cases when reified generics are a giant pain in the butt and non-reified ones are the right solution. See Scala or F# and .NET interoperability.
Once you're in byte code, you don't have your static types anymore -- that is, types that are independent of control flow. You have types on individual instructions.
So basically you lost some type information before the JIT even sees it. Now, it doesn't actually matter for speed, as Mike Pall (LuaJIT author) would say. His point is that dynamically typed languages can be just as fast as statically typed languages, because you have more information at runtime.
I guess he meant JavaScript. JavaScript is dynamic and JS JITs try to reconstruct types at runtime to improve performance. Java is statically typed and, with a minor exception of generic type arguments, types are accessible both at compiletime and runtime.
Is it a fictive analogy or is it actually how the Java VM behaves?