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
Related
I have these 3 classes
public class Box<O> {
public O getItem() {...}
}
public class CoolBox extends Box<Integer> { ... }
public class AmazingBox extends CoolBox { ... }
At one point in my code, I need to get the return Type of the method getItem() for the AmazingBox class, but when accessing its methods via reflection, I get Object as the return Type instead of Integer.
Is there any way, (plain java or extra libraries) to get Integer as the return Type?
This is the code I used to get the return type:
Class<?> c = AmazingBox.class; // This is not how i get the class but its for demonstration purposes
Method m = c.getMethod("getItem");
Type t = m.getReturnType();
I just discovered that there is a library called GenericsResolver that does exactly what I want.
Using this piece of code it returns the correct type
Class<?> clazz = AmazingBox.class;
GenericsContext genericsContext = GenericsResolver.resolve(clazz);
Method method = clazz.getMethod("getItem");
Type methodReturnType = genericsContext.method(method).resolveReturnType();
While inheriting you can use generics for inheriting classes and create lower or upper bounds accordingly. If you don't do that assume you are working without using generics and won't get type safety on inheriting non-generic classes.
In short, if you go hybrid, type erasures will become effective with following rules (ref- oracle documentation)
Type Erasure
Generics were introduced to the Java language to provide tighter type checks at compile time and to support generic programming. To implement generics, the Java compiler applies type erasure to:
Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods.
Insert type casts if necessary to preserve type safety.
Generate bridge methods to preserve polymorphism in extended generic types.
Type erasure ensures that no new classes are created for parameterized types; consequently, generics incur no runtime overhead.
I want to write a quick and dirty helper class which can quickly save my objects. Therefore I'm using OrmLite.
I don't want to add annotations on my classes, so I try to add a wrapper on the fly, without any bytecode-libs.
<T> void save(T o) {
#DatabaseTable
class wrap extends T {
#DatabaseField(generatedId = true)
public Long id;
}
try {
Dao<T, Long> d = (Dao<T, Long>) getClassDao(o.getClass());
TableUtils.createTableIfNotExists(connectionSource, o.getClass());
d.createOrUpdate(o);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
The problem is class wrap extends T - why is it not possible to extend T?
This is a weird but interesting question! It's tricky to give an exact and exhaustive answer. There are probably a lot of different reasons, but I think the following one is the most important:
Only one version of save will ever be generated by the compiler. For class wrap extends T to work the parameter T would have to be a different concrete classes for every use of save with a different type, but that is not how generics work. save is compiled only one time, and inside save T is a type parameter, not a concrete type. (This is somewhat related to, but different from type erasure, see below.)
Another reason is type erasure. Generic types in Java is something that only exists at compile time. A class in Java on the other hand has a runtime representation (in contrast to, for example, C++). So there is no possibility that the runtime representation of a class could be generated from the compile-time-only construct that a generic type is.
<T> is a generic type, not a real class. A generic type is a compile time concept, it get erased at runtime, while a class is a runtime stuff and it does have corresponding bytecode. You can't declare a sub class of generic type <T> because compiler has no idea what that super class is
Because T could be final. Final classes cannot be extended.
At least this is a logical reason that prohibits extending a generic type. The technical background is explained in other answers.
I'm looking to access the generic type of a declared field during runtime. I was previously under the impression that this was not possible due to the Java type erasure. However, this must not be the case because some well known frameworks leverage the generic type through reflection during runtime.
As an example, Guice will implement a Provider based upon the generic type you provide:
public class Injectable{
#Inject
private Provider<SomeType> someTypeProvider;
}
How does one access the 'SomeType' generic attribute of a field or any such type/method/etc through the reflection API?
Additionally it would be helpful to also know how to access these generic type attributes through the Java 6 Annotation Processor API.
Thanks.
Edit:
Thank you all for your great pointers. I found a way to do this using haylem's links, specifically the one to Prenkov's article Java Reflection: Generics.
Here's the answer I was looking for:
/**
* #author John Ericksen
*/
public class TypeReflectionExample {
public class SomeType{}
public class Injectable{
#Inject private Provider<SomeType> someTypeProvider;
}
public static void main(String[] args){
try {
Field providerField = Injectable.class.getDeclaredField("someTypeProvider");
Type genericFieldType = providerField.getGenericType();
if(genericFieldType instanceof ParameterizedType){
ParameterizedType aType = (ParameterizedType) genericFieldType;
Type[] fieldArgTypes = aType.getActualTypeArguments();
for(Type fieldArgType : fieldArgTypes){
Class fieldArgClass = (Class) fieldArgType;
System.out.println("fieldArgClass = " + fieldArgClass);
}
}
} catch (NoSuchFieldException e) {
e.printStackTrace();
}
}
}
results in:
fieldArgClass = class test.TypeReflectionExample$SomeType
The same can be done for Methods, Constructors, Superclass extensions/implements, etc
I'm awarding haylem, as his post led me to this solution, even if it didn't directly answer my question.
It is true that generics aren't generally known at runtime in Java, because they are implemented with Type Erasure.
Reflecting Generics?
However, you can stil extract some valuable information about the declared types (NOT the runtime objects' types), as presented in Ian Roberston's article Reflecting Generics and Prenkov's article Java Reflection: Generics.
Background on Generics and Type Erasure
Generics where introduced while conserving backwards compatibility at the source qnd binary level, hence some of their limitation, like:
the impossibility to have a short-hand form without at least some indicator for generics support (here, the so-called diamond operator <>),
the impossibility to inspect generic-types at runtime, because they had to be implemented with Type Erasure.
Further Reading
From The Java Tutorial:
section on Generic Types
section on Type Inference and Instantiation of Generic Classes
From the Java Language Specifications (JLS):
Java SE 5's JLS section on Types, Values and Variables
Java SE 7's JLS section on Types, Values and Variables
From good StackOverflow questions:
Java Raw Type and generics interaction
Others:
IBM Developer Series: Java Theory and Practice: Generics Gotchas (especially the sections The Road Not Taken, Generifying Existing Classes and Implications of Erasure).
Well, why don't you look at what guice does? The source is publicly available.
Guice does these things at multiple levels. One that particular sticks out are type literals.
The key point here is that while types are compiled using type erasure (so there is only one class for each type), there still exist multiple Type objects, that do know the generics used. However, the code is optimized independently of that (as it was compiled per class, and not per type).
Have a look at the Java API of ParameterizedType.
So while it is correct that Java Generics are implemented by "type erasure" on a class level, this doesn't completely hold on a Type level. Unfortunately, handling Types is much more tricky than classes. Plus, this also implies that Java cannot optimize generics in the same way that C++ does, in particular for primitive types. An ArrayList<Integer> will by design be an ArrayList<?> containing objects, and not backed by a native int[] array when possible.
Note that this is, however, rather close to keeping track of these things yourself. Say, very naively (it will not work with nested generics), you could just extend ArrayList<T> with a class, that has a field Class<T> contentClass, then you will be able to find out this information at runtime. (A TypeLiteral may be the better choice instead of a Class here, though!) Plus, the JRE will actually not ensure that the list remains consistent. Just like you could cast a ArrayList<Integer> into an untyped ArrayList and add a String object.
I've used this a year or so ago. It could help you out
Type typeOfSrc = type(YourClass.class, clazz);
// type(C, A1,...,An) => C<A1,...,An>
static ParameterizedType type(final Class raw, final Type... args)
{
return new ParameterizedType()
{
public Type getRawType(){ return raw; }
public Type[] getActualTypeArguments(){ return args; }
public Type getOwnerType(){ return null; }
};
}
This allows you to access the Generic type at run time. Basically what you're doing here is storing the Generic information in another class, and using that class for retrieving that information at run time.
I believe guice uses TypeLiteral to encapsulate generic information in a separate object.
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.
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.