Java Generics & Reflection - java

this probably is a basic question, but can I do something like this:
Class myClass = Class.forName("Integer");
SomethingSimple<myClass> obj;
Where SomethingSimple is a very simple generic class:
class SomethingSimple<T>
{
T value;
SomethingSimple() {}
public void setT(T val)
{
value = val;
}
public T getT()
{
return value;
}
}
Obviously, the code above is not correct, since myClass is an object of type Class, and a class is required. The question is how can this be achieved. I read the other topics about Generics Reflection, but they concerned how the generic class knows the type.

No, you can't do that. What's the point? Generics give you compile-time type checking and if the class isn't known until runtime, you don't gain anything.

Generics in Java are used only for static type checking at compile time; the generic information is discarded after type checking (read about type erasure) so a SomethingSimple<Foo> is effectively just a SomethingSimple<Object> at runtime.
Naturally, you can't do comple-time type checking on a type that isn't known until runtime. The type has to be known to the compiler, which is why you have to use an actual type name rather than a Class variable as the generic type parameter.

Generics is a compile time mechanism to ensure type safety, and reflection is a runtime mechanism. What you're saying is, "I don't know at compile time what the type of T is but I want compile time type safety" (which doesn't make much sense). To put it another way, java erases the type of T at runtime and stores it as an Object...so the type of T (as far as generics are concerned) no longer matters.
But really it seems like you want a dependency injection container, like spring or google guise.

Related

Get the type of generic T

C# allows for getting the type of generic parameters using the typeof(T)method without the need to instantiating the T parameter. But in Java anytime I have generic T parameter and I want to determine the type I have to create an instance of that parameter,for example by using the Class<T> Type, to figure out what type that is.
In comparison with what C# provides, this approach in Java looks unnecessarily lengthy and complicated.
I would like to know what is best alternative to determine the type of a generic parameter without the need to instantiate that (for example if (T is Integer)).
Generics in Java is a compile-time feature - thus the mismatch between Java and C#. As a result you cannot do anything at run time to determine the type unless you are either passed an object of the type or create one yourself or actually told the class in some other way.
It is generally considered a bad idea to even try to find the type. It generally indicates that you have not designed your class hierarchy properly.
Generics are compile-time true... but you can give the compiler hints of what t really is.
by passing in the actual runtime class of what T really is, you allow the compiler to allow you runtime knowlege of the class T represents.
example:
public <T> boolean isObjectT(Class<T> type, Object object){
return object.getClass().isAssignableFrom(type);
}
The answer on this question kinda spells out the limits of parameterized types:
Java: How do I specify a class of a class method argument?
If you are simply trying to get information from subclasses... you could try the reflection with paramterized types on this question:
How to determine the class of a generic type?
I have had good luck with that for more complex requirements.

Reusable interface that uses generics

I want to create a single class that refers to a type of service using an interface. The service can have different implementations. The different implementations will process different types of requests. In the past I would define an interface something like this:
public interface I_Test
{
public String get(String key, Enum type);
}
and implement it like this:
public class Test_1 implements I_Test
{
public String get(String key, Enum type)
{
Enum_1 t1 = (Enum_1)type;
switch(t1)
{
case NAME:
return "Garry";
case DOB:
return "1966";
default:
throw new IllegalArgumentException("Unkown type [" + type + "]");
}
}
}
The good is I can use a different implementation of my interface to meet different needs.
The bad is I have to type cast and so have a risk at runtime.
I was hoping that generics could solve this, so I did this:
public interface I_Test<T extends Enum>
{
public String get(String key, T type);
}
and this:
public class Test_1 implements I_Test<Enum_1>
{
public String get(String key, Enum_1 type)
{
switch(type)
{
case NAME:
return "Garry";
case DOB:
return "1966";
default:
throw new IllegalArgumentException("Unkown type [" + type + "]");
}
}
}
but when I go to use the thing I get type safety warnings unless I declare my variable with the type I intend to use, like so:
I_Test<Enum_1> t1 = new Test_1();
This really bugs me because the whole point of creating the I_Test interface was so that I could use different implementations but it seems I have to lock in to a particular type at compile time to avoid this warning!
Is there any way to write a reusable interface that uses generics without this annoying warning?
The point of generics is to ensure that your code is more reliable (as far as type-safety is concerned). With generics, you are able to find out about type incompatibilities at compile-time instead of runtime. When you defined your interface as I_Test<T extends Enum>, you are basically saying that you do need the interface to be genericized according to a specific type. This is why Java is giving you a warning.
You would get the same warning if you did something like this Map myMap = new HashMap<string>();.
In Java, you actually specify the types and they are not inferred from what is on the RHS (unless you do something like Integer i = 1, but that's autoboxing). Since you genericized your interface, when you declare something using that interface, you need to specify the type to use (to genericize).
When you instantiate a generic type, the compiler will translate those types by using something called "type erasure". Here, the compiler removes all information associated with the type parameters and type arguments. Java does this to maintain compatibility with older code that was written before Java had generics.
So I_Test<Enum_1> is actually translated to the raw type I_Test during compilation. Using a raw type is generally considered to be a bad practice (hence, the "annoying warning"). The compiler is telling you that it does not have enough information to perform type-checking and therefore it cannot ensure type-safety (because you used a raw type).
To learn more about generics, take a look at the following:
Oracle's page on Generic Types
Angelika Langer's FAQs about Generics
Generics is about compile time warnings. If you don't want them, don't use them.
Having said that, you can create different, non-generic subinterfaces, for example:
public interface Enum_1_Test extends I_Test<Enum_1> {
...
}
And then declare your class as
public class Test_1 implements Enum_1_Test
But I'm not convinced this is very useful. As a rule of thumb, you want to use generics if you have one implementation that works for many input types and use the good old polymorphism if you want a separate implementation for each input type.
The raw I_Test supports any enum type as argument while the Test_1 implementation only supports a limited subset (Enum_1), this is because Test_1 is specified as implementing I_Test only for one enum type.
Here is an example why the compiler issues a warning, the following code compiles since the raw type of I_Test accepts any enum, however as Test_1 only supports Enum_1 it will throw a class cast exception.
enum MyEnum{A}
I_Test t1 = new Test_1();//warning here
t1.get("",MyEnum.A);//Exception at runtime, but compiles fine
If you specify the generic type it will cause a compilation error, this is preferred to runtime exceptions.
enum MyEnum{A}
I_Test<Enum_1> t1 = new Test_1();
t1.get("",MyEnum.A);//Does not compile

Why is Class<?> preferred to Class

If I declare a Class as a field:
Class fooClass;
Eclipse gives me the warning:
Class is a raw type. References to
generic type Class should be
parametrized
What does this mean in practice? and why am I urged to do it? If I ask Eclipse for a "quick fix" it gives me:
Class<?> fooClass;
which doesn't seem to add much value but no longer gives a warning.
EDIT: Why is Class generic? Could you please give an example of parameterization, i.e. could there be a valid use of something other than <?> ?
EDIT: WOW! I had not realized the depths of this. I have also watched the Java Puzzler and it's certainly scared me about the bear traps. So I will always use
Class<MyString> myStringClass = MyString.class;
rather than
Class myStringClass = MyString.class;
(But having used Java from day one, I didn't really notice when Class became generic);
NOTE: I have accepted #oxbow_lakes as this makes sense to me, but it is clearly a very complicated area. I would urge all programmers to use the specific Class<MyString> rather than Class. And Class<?> is much safer than Class.
Raw Types and Unbounded Wildcards
None of the previous answers have really addressed why you should prefer Class<?> over Class, as on the face of it, the former seems to offer no more information than the latter.
The reason is that, the raw type, i.e. Class, prevents the compiler from making generic type checks. That is, if you use raw types, you subvert the type-system. For example:
public void foo(Class<String> c) { System.out.println(c); }
Can be called thusly (it will both compile and run):
Class r = Integer.class
foo(r); //THIS IS OK (BUT SHOULDN'T BE)
But not by:
Class<?> w = Integer.class
foo(w); //WILL NOT COMPILE (RIGHTLY SO!)
By always using the non-raw form, even when you must use ? because you cannot know what the type parameter is (or is bounded by), you allow the compiler to reason about the correctness of your program more fully than if you used raw types.
Why have Raw Types at all?
The Java Language Specification says:
The use of raw types is allowed only as a concession to compatibility of legacy code
You should always avoid them. The unbounded wildcard ? is probably best described elsewhere but essentially means "this is parameterized on some type, but I do not know (or care) what it is". This is not the same as raw types, which are an abomination and do not exist in other languages with generics, like Scala.
Why is Class Parameterized?
Well, here is a use-case. Suppose I have some service interface:
public interface FooService
And I want to inject an implementation of it, using a system property to define the class to be used.
Class<?> c = Class.forName(System.getProperty("foo.service"));
I do not know at this point that my class, is of the correct type:
//next line throws ClassCastException if c is not of a compatible type
Class<? extends FooService> f = c.asSubclass(FooService.class);
Now I can instantiate a FooService:
FooService s = f.newInstance(); //no cast
which doesn't seem to add much value
but no longer gives a warning.
You're right. But this might add value:
Class<FooClass> fooClass;
or, if more appropriate:
Class<? extends FooClass> fooClass;
or
Class<FooInterface> fooClass;
As with generics in general, you can improve type safety by specifying what kind of class you want the variable to hold. The warning against raw types is just meant to catch pieces of code where this potential is not used. By declaring Class<?> you're basically saying "this is meant to hold any kind of class".
Because, since JDK 5, Class has now have parameterized type, which makes Class a generic object. This is necessary (since the introduction of Generics) for the compiler to do type checking (at compile time, of course).
Class<?> means a "class of unknown" where ? is a generics wildcard. It means a that fooClass of type Class<?> accepts a Class whose type matches anything.
Typical example:
Class<?> classUnknown = null;
classUnknown = ArrayList.class; //This compiles.
You can, effectively, provided a Parameterized Type to be more specific, e.g.:
Class<ArrayList> = ArrayList.class;
PS Bear in mind, that Class<List> listClass = ArrayList.class; won't compile (even though ArrayList is of List) but (as Mark Peters mentioned on the comment) Class<? extends List> listClass = ArrayList.class; does compile (thanks to the wildcard).
The Javadoc of the Class class does give some idea about why type parameters exist for this class:
T - the type of the class modeled by
this Class object. For example, the
type of String.class is Class<String>.
Use Class<?> if the class being
modeled is unknown.
The use of this type parameter is not so obvious, but a cursory look at the source code of the class, indicates why the type parameter is sometimes necessary. Consider the implementation of the newInstance method:
public T newInstance()
throws InstantiationException, IllegalAccessException
{
if (System.getSecurityManager() != null) {
checkMemberAccess(Member.PUBLIC, ClassLoader.getCallerClassLoader());
}
return newInstance0();
}
If one hasn't noticed, the type of the object returned by this method is that of the type parameter. This is useful in code that utilizes a lot of reflection, and where one would like to be extra careful to ensure that objects of the right type are being instantiated.
Considering the example in the question, if the class instance was instead declared as:
Class<String> fooClass;
Class<Integer> barClass;
String aString;
then, it is next to impossible to have the following code to compile:
aString = barClass.newInstance();
In short, if you're going to be working with class hierarchies and you wish to impose strict compile time checks to ensure that your code does not need to perform a lot of instanceof checks, then you're better off specifying the type of the class that you wish to utilize. Specifying ? allows all types, but there would be cases when you'll need to be more specific.
Because using raw types instead of parameterized types has many pitfalls.
One of which is that if a raw type is used, all generics on the class are lost. Even those defined per-method.

Generic method in Java, determine type

I would like to be able to detirmine the return type of my method call at runtime, but I can not seem to be able to get the Type of T.
public <T> T getT()
{
Object t = null;
Class<?> c = t.getClass();
System.out.println(c.getName());
return (T) t;
}
Is there any way to determine the Type of T at runtime in Java?
Your function will throw a NullPointerException, because you call "getClass" on a null pointer (since t is initialized with null). Additionally, generics are used for giving added compile-time type-checking. They do not give you anything special at runtime; generics simply use type Object, but cause the code which uses the generic object to perform implicit casts and also causes the compiler to be aware of how you will use it.
Java generics are a static type checking feature. Attempting to retrieve reflection artifacts from generic parameters is typical of poorly thought out design.
In the question example, there is no guarantee that T is a class or even interface. For example
List<? extends Frogs> list = thing.getT();
If you really want to go down this path (and I strongly suggest you don't, not that I expect you to take any notice), then you can supply a reflection object that is statically related to the generic parameter as an argument:
public <T> T getT(Class<T> clazz) {
Object value = map.get(clazz);
return clazz.cast(value);
}
If you have a generic Class you can write a constructor that takes the type and saves it into a member of your class. This way you can check the Type during runtime. All information that are only in the generics are gone after compiling.

Why is Java's Method class not generic?

That would allow the invoke method to have the right return type. For instance:
class Method<T> {
T invoke(Object obj, Object... args);
}
In Java, Generics are only available at compile time. You cannot determine the Generic type at runtime. This allowed the generics implementation to be backwards compatible with old versions of the JVM.
Since generics are only available at compile time, if you know the type of your class then you do not need to use reflection.
It would have been not unreasonable to make Method generic on erased return type. However, it would be a lot of effort with little gain. The nature of reflection is that you don't know the types at compile-time - otherwise you could statically link.
I guess you could in some case even add new APIs so that the generic type is returned. The information is still on the method, although not from the instance that you pass to it.

Categories