I have following java sample class:
public class TestClass {
public static <T> void method(List<T> objects) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
T obj = (T) objects.get(i).getClass().newInstance();
}
}
}
It is producing a compiler warning:
Type safety: Unchecked cast from capture#1-of ? extends Object to T
I can perfectly obtain the exact T object, if I just do:
T obj = objects.get(i);
Which it knows perfectly is of Type T.
Why I am not able to create a new instance of that class? How could I fix it?
(I am not looking for a response of type: 'Add @SuppressWarnings("unchecked")')
In JavaScript, there is the ability to create a generic anonymous object to serve this purpose. It can either be created using new Object() or the shorthand { ... } syntax, and can then be given any properties or methods that are needed.
This happens because getClass()
returns a Class<? extends Object>
. You cannot (safely) cast the wildcard ?
to anything, not even a generic class type. This is a limitation of Java Generics. But since you can be sure this warning is not a problem you can safely ignore or suppress it.
But here is a workaround, many applications and libraries do this:
public static <T> void method(List<T> objects, Class<T> clazz) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
T obj = clazz.newInstance();
}
}
Generics are erased at runtime. So invoking getClass()
on a declared T
element of the list returns a <? extends Object>
class instance.
Object.getClass()
states indeed :
The actual result type is
Class<? extends |X|>
where|X|
is the erasure of the static type of the expression on which getClass is called.
To invoke newInstance()
and create an instance of T
you need to know the Class
instance which you want to instantiate but note that the List
can contain any subclass of T
, so passing a class as parameter may not be enough.
For example :
List<Animal> list = new ArrayList<>();
list.add(new Lion());
list.add(new Rabbit());
list.add(new Turtle());
Which one invoked now ?
method(list, Lion.class);
method(list, Rabbit.class);
method(list, Turtle.class);
No one as anyone will compile ! So it is clearly not enough.
So I think that it makes more sense to keep your original code by suppressing the warning. In this way you ensure that you will create an instance of the same class that the actual element in the list :
public static <T> void method(List<T> objects) throws Exception {
for (int i = 0; i < objects.size(); i++) {
// Create new object of the same class
@SuppressWarnings("unchecked")
T obj = (T) objects.get(i).getClass().newInstance();
System.out.println(obj);
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With