Java generics - gain access to parameters - java

I have next code:
class iCache<K,V> implements Map<Object, Object>
{
...//Code
}
How can I get the class name of K and V?

You can't, the compiler performs type erasure at compile time. In other words, the K and V type parameters are purely a compile time notion, they aren't accessible at runtime.
What you can do is to grab the class of the key/values in your custom Map type at runtime.

You can't. Java generics don't work that way. At runtime, there is no class-specific information available (this is known as erasure). If you really need this information, you will have to pass in e.g. Class objects.

If you extend iCache and want to obtain the typer parameters you used to declare the subclass (like below):
class someCache extends iCache<Integer,Long> {
//...
}
You can find out those parameters at runtime using the following (source):
Class clazz = ((ParameterizedType) getClass()
.getGenericSuperclass()).getActualTypeArguments()[0];
If you provide the parameters at instantiating like this
iCache<Integer,Long> cache = new iCache<Integer,Long>();
then you are out of luck (more info).

The types will get erased. Pass in Class and Class as args into the constructor to pass through your raw types. Store as fields. Note: your patameterisation is bad anyway: you need to pass K and V to Map as well, or you'll give yourself more pain.

Actually you can, call the getClass() method on the key and value

Related

Java Generics with class object as generic type

I want to create a Java Object for a class that is defined using generics.
Specifically, i want to create a List of Objects of class that is determined at runtime.
I would want something like
Class clazz = Class.forName("MyClass");
List<clazz> myList = new ArrayList<>(); // This isn't allowed
Defining an array of object would allow me to store a list of MyClass type objects, but that would lead to casting the objects every-time the object is fetched from the list, i would like to avoid such a scenario.
Is there a way to achieve something like the above code using java.
Well, since you know that class, you could (with a warning) cast the List itself; but you would still need to know the class name and some checks for that, like for example:
if(clazz.getName().equals("java.lang.String")) {
// warning here
yourList = (List<String>) yourList;
}
As I understand your question, you want to know if is possible for the compiler to know the runtime type while it is limited to the compile type.
You can't. And your hypothesis is also wrong:
Defining an array of object would allow me to store a list of MyClass
type objects, but that would lead to casting the objects every-time
the object is fetched from the list, i would like to avoid such a
scenario.
In Java, generics does not remove the cast: it is still there in the form of type erasure and (hidden) cast. When you do List<String>, you merely ask the compiler to hide the cast in operation such as T get(int): there will be a cast to String.
If you want to use the compile time information, than that would mean you already have/know the type MyClass available at compile time and you would not use Class::forName but MyClass.class which would return a Class<MyClass>.
What you can do is either:
Use an interface if you have a common ground for theses classes (like JDBC Driver).
Cast the raw list into a known type, for example using Class::isAssignableFrom.
No, you can't. Generics in Java is just a compile-time type checking mechanism. If you don't know the type until runtime, then, obviously, it cannot be used for compile-time type checking. The compiler can't determine at compile time what types to allow you to put into or get out of a List<clazz>, so it's no more meaningful than just a raw type List.
There is a little trick that can be used to work with a specific unknown type: Declare a type parameter that is only used for the unknown type:
public <T> void worksWithSomeUnknownClass() throws ReflectiveOperationException {
#SuppressWarnings("unchecked")
Class<T> clazz = (Class<T>) Class.forName("MyClass");
T obj = clazz.getConstructor().newInstance();
List<T> myList = new ArrayList<>();
myList.add(obj);
}
This solution is very limited though. It makes sure that you don't mix it up with other unknown types or Object, but you can not really do anything with T. And you have to declare a type parameter on every method that uses it.

Define a generic type with a class object at runtime

Is it possible to declare the type of a generic using a class object?
For instance, I would like to do something like this:
Class returnType = theMethod.getReturnType();
AttributeComponent<returnType> attComponent;
attComponent = new AttributeComponent<returnType>(returnType, attName);
attributeComponents.put(methodName.substring(3), attComponent);
Now I know obviously this is incorrect, but is there a way to achieve this?
EDIT: explaining a little bit
I'm using reflection to go through all getters and then generate a UI element for each property (the AttributeComponent class, which has a JComponent element and a JLabel). I would like to use generics in order to create a getValue() method that would return an object of the property type.
I do not know if there is a way to compile something like that, but it has little value.
Think that thanks to type erasure, the compiled classes do not use the Generics information. That is, doing a Set<String> a = new Set<String>(); is useful for checking the use of a at compile time, but not at runtime.
So, you want to instantiate a Generic whose type will be only known at runtime, but at runtime it will not be used.
I would say this can be achieved by defining the method return type as generic; but you need to pass the actual type as a class argument to use it like you've shown:
<T> T yourMethod(Class<T> returnType) {
// use <T> as generic and returnType to refer to the actual T class
/* ... */ new AttributeComponent<T>(returnType, attName);
}
It would be also useful to see the larger context for what you're trying to do. If you want AttributeComponent.getValue() to return some generic type T (which is the method return type), that's completely useless unless you know each method return type at compile time, otherwise T will be nothing more than an Object. In my example above, you call yourMethod with a class that you already know and the same type will be returned (or some AttributeComponent of that type or whatever).

What does the generic nature of the class Class<T> mean? What is T?

I understand generics when it comes to collections. But what does it mean in the case of the Class<T> class? When you instantiate a Class object, there's only one object. So why the T parameter? What is it specifying? And why is it necessary (if it is)?
Type parameter <T> has been added to java.lang.Class to enable one specific idiom1 - use of Class objects as type-safe object factories. Essentially, the addition of <T> lets you instantiate classes in a type-safe manner, like this:
T instance = myClass.newInstance();
Type parameter <T> represents the class itself, enabling you to avoid unpleasant effects of type erasure by storing Class<T> in a generic class or passing it in as a parameter to a generic method. Note that T by itself would not be sufficient to complete this task2: the type of T is erased, so it becomes java.lang.Object under the hood.
Here is a classic example where <T> parameter of the class becomes important. In the example below, Java compiler is able to ensure type safety, letting you produce a typed collection from a SQL string and an instance of Class<T>. Note that the class is used as a factory, and that its type safety can be verified at compile time:
public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
Collection<T> result = new ArrayList<T>();
/* run sql query using jdbc */
for ( /* iterate over jdbc results */ ) {
T item = c.newInstance();
/* use reflection and set all of item’s fields from sql results */
result.add(item);
}
return result;
}
Since Java erases the type parameter, making it a java.lang.Object or a class specified as the generic's upper bound, it is important to have access to the Class<T> object inside the select method. Since newInstance returns an object of type <T>, the compiler can perform type checking, eliminating a cast.
1 SUN Oracle has published a good article explaining all this.
2 This is different from implementations of generics without type erasure, such as one in .NET.
3 Java Generics tutorial by Oracle.
The answer by dasblinkenlight already demonstrated one of the main uses of this parameter. There is one more aspect I consider relevant: using that parameter, you can restrict the kind of class you want to pass at a given location. So e.g.
Class<? extends Number> cls
means that cls may be any class implementing the Number interface. This can help catching certain errors at compile time, and makes class argument requirements more explicit.
Perhaps a comparison to the case without generics is in order
// Java ≥5 with generics // Java <5 style without generics
Class<? extends Foo> c; Class c;
Foo t1 = c.newInstance(); Foo t1 = (Foo)c.newInstance();
Object obj; Object obj;
Foo t2 = c.cast(obj); Foo t2 = (Foo)c.cast(obj);
As you can see, not having T as an argument would require a number of explicit casts, as the corresponding methods would have to return Object instead of T. If Foo itself is a generic type argument, then all those casts would be unchecked, resulting in a sequence of compiler warnings. You can suppress them, but the core issue remains: the compiler cannot check the validity of these casts unless you properly use the type argument.
In Java there's a single metaclass: Class. Its instances (only one per type exists) are used to represent classes and interfaces, therefore the T in Class<T> refers to the type of the class or interface that the current instance of Class represents.
The use of generics in the Class type is top define the type of class. If I have ' Class obj' my object obj can holds only children of Charsequence.
This is an optional argument. I'm often put an '?' to avoid warnings from the Eclipse IDE if I don't need an specific type of class.

Generics: Get name of instance

I have a method which returns a List<Property<?>>.
Property is a type having one generic parameter:
public class Property<T extends Comparable<T>> { ... }
Having a list of mixed-typed properties, I cannot know what type parameter a specific element has.
I would like to do something like that:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
// I know this doesn't exist ----^
}
In one sentence: I need the PropertyWrapper to have the same generic template argument as the current Property does. Is there any way to do this?
I could apply a suggestion as stated in https://stackoverflow.com/a/3437930/146003 but even if I do this, how to instanciate the appropriate PropertyWrapper<XXX> then, only having an instance of Class<T>?
I can modify Property<?> if required. I also don't mind if reflection needs to be used (I assume it needs to be)
EDIT: I forgot something. In fact I cannot instanciate the wrapper by the line
PropertyWrapper<?> crtWrapper = new PropertyWrapper(crt.getGenericType());
because I have specialized subclasses (PropertyWrapper_String).
Now I see two possibilities:
1: Instanciate the class by string:
String strGenericType = "";
Class<?> wrapperClass = Class.forName("PropertyWrapper_" + strGenericType);
2: Is there any way to specialize a generic class without creating a subclass?
Many thanks in advance for your tips
Try creating the following method:
<T> PropertyWrapper<T> createWrapper(Property<T> property){
return new PropertyWrapper<T>(property);
}
Then call it as such.
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = createWrapper(crt);
}
The reason the above works is that the generic type T is inferred from the argument and is locked down for the entire method. Unlike using <?> in the loop where each instance of <?> is inferred to be a different type.
Edit:
To deal with the issue of having a different class type depending on the class in the wrapper, consider a Map where the key is the class being wrapped and the value is the wrapper.
Map<Class<?>, Class<?>> myMap;
Then you could so something like this:
Class<?> wrappedType = property.getGenericType();
Class<?> wrapperClass = myMap.get(wrappedType);
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) wrapperClass.newInstance();
Although you might need to do something like this if you need to pass an argument.
Constructor<?> constructor = wrapperClass.getDeclaredConstructor(property.getClass());
PropertyWrapper<?> wrapper = (PropertyWrapper<?>) constructor.newInstance(property);
If you have a Class<T> you can just take that class, create an instance by calling newInstance() on the class object and cast it to T.
The problem you have is getting the generic parameter of crt. If you have concrete subclasses of Property, e.g. StringProperty extends Property<String>, you can get the type using reflection. However, if you only create instances of Property<T> without concrete subclasses and you don't know where the elements of the list are created, AFAIK it is impossible to get the generic type (even if you know where the elements are created it might be impossible though).
Thus, the only way you might get the property wrapper to know the type of the property might be to store the type parameter (the class) in the property itself. Then the wrapper could query the property for its type/class member variable.
Edit: some explanation on why this is impossible or at least very hard.
The problem with generics is that due to type erasure the generic type is lost when you create a property using new Property<SomeType>(). There's just no runtime information that you could use to retrieve SomeType here.
If you have concrete subclasses (defining concrete generic types) you have reflection information available at runtime of what where the generic parameters of each class. Then you could get the actual class of each property and retrieve the reflection data for that class.
This would also be possible if you have methods or fields that define those types and return/hold references to a propery. However, I doubt you have that information since you seem to get some list and don't know exactly on where and how the elements of that list were created.
I further assume the properties' class is Property only, not a subclass. Thus the only way is to provide the runtime information yourself, i.e. by passing a reference to the type class as a constructor parameter.
Okay I'm going to answer myself.
I'm now passing an instance of Class<?> to the Property-class.
Then I extract the basic name of the property and simply cut away "java.lang." which is possibly as in most cases, I'm doing this to primitive data types - resp. their autoboxing classes.
Further, I just instanciate a new instance of the wrapper by name and pass the to be wrapped property as a parameter to the constructor which applys for that.
Here some code for the interested ones among you:
String template = "..."; // some package definition
for (Property<?> crt : bag)
{
String className = template + crt.getClassName();
Class<? extends PropertyWrapper<?>> wrapperClass = null;
wrapperClass = (Class<? extends PropertyWrapper<?>>) Class.forName(className);
Constructor<? extends PropertyWrapper<?>> constructor = wrapperClass.getConstructor(new Class<?>[] {Property.class});
PropertyWrapper<?> wrapper = constructor.newInstance(crt);
// Further operations using the wrapper
}
for simplicity, I left out the error handling part.
Rather than instantiating the wrapper from the call site, why not have the Property know how to create its own wrapper? Something like:
public class Property<T extends Comparable<T>> {
PropertyWrapper<T> newWrapper();
}
That only half-helps, though. Your real problem is that in a loop like yours:
List<Property<?>> list = getList();
for(Property<?> crt : list)
{
PropertyWrapper<?> crtWrapper = crt.newWrapper();
}
The fact that the PropertyWrapper and the Property have the "same" type isn't very helpful, since that type is just the unbound wildcard.
I really hate to give one of those "what are you really trying to do" answers, but -- what are you really trying to do? Generally speaking, once you get to an unbound wildcard, all hope is lost (unless you're willing to do unsafe, uncheckable casts or bend over backwards with reflection checks). One way around this is to put as much of the action within the Property<T> as possible,before you put that property in the List<Property<?>>. My newWrapper() is an example of this: it puts the action of creating a PropertyWrapper<T> into the Property<T> itself. If you wanted to register a callback for when the property changed, that's also something you may be able to do at each place you instantiate a non-wildcard Property<Whatever>. For instance:
Property<UserLogin> property = new Property<UserLogin>();
SomeListener<UserLogin> listener = whatever();
property.addListener(listener);
wildcardedPropertiesList.add(property);
This particular example probably won't help, but hopefully it'll give you applicable ideas.

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.

Categories