Generics are mostly a compile-time tool helping the compiler spot casting errors. Due to type erasure most of the generic information is lost at runtime - besides some basic information in reflection data (which doesn't really help you here).
Let's assume your constructor looks like this:
public SomeClass( Class<T> param ) { ... }
Due to type erasure at runtime it looks like this (when being called):
public SomeClass( Class param ) { ... }
As you can see there's no generic information so to get it you'd use SomeClass.getConstructor( Class.class )
.
Then you can invoke it using newInstance( Class.forName("java.lang.String") )
.
Again you see that you're basically able to pass in any class as a parameter which is due to generics being a compile-time tool, i.e. the compiler applies those checks while the runtime trusts the compiled code.
If you need to employ any boundaries you'd need to either use a different approach or check for the correct class being passed inside the constructor (e.g. by using the method Class#isAssignableFrom()
).
When assigning the created instance to a variable you need to use a wildcard, i.e. SomeClass<?> sc
, or a raw type, i.e. SomeClass sc
(I'd suggest using the wildcard). Of course the compiler then can't allow you to call any method that is only present in some classes (e.g. in MyClass
) since it simply doesn't know (and it can't know the class definition from just a name).
Edit:
In the hope of being able to clarify the last part I'll try and add another example.
Assume MyClass
had a method foo()
and SomeClass
has a method T getTypeInstance()
. If your variable type would be SomeClass<MyClass> sc
you could do a call sc.getTypeInstance().foo()
since the compiler knows that T
is bound to MyClass
.
However, when using reflection that information is lost, i.e. since you'd have to use SomeClass<?> sc
the compiler would not know the return type of getTypeInstance()
and thus wouldn't allow calls to foo()
.
If you know that all classes you could pass as a parameter implement the same interface you could do something like SomeClass<CommonInterface> sc
which would compile since Constructor#newInstance()
returns a raw type and thus compiler checks are disabled here. In that case you could add foo()
to CommonInterface
and be able to call it - at least unless you break the code.
The problem with the above is that you could also pass String.class
to the constructor, which the compiler and runtime would allow but which is still wrong since String
doesn't implement CommonInterface
. Hence you'd get exceptions when trying to create the instance, cast it to CommonInterface
or call foo()
on it - unless you add a check in your constructor that rejects any parameter that isn't a class being assignable to CommonInterface
(e.g. by checking CommonInterface.class.isAssignableFrom( param )
).