Reputation: 4391
for performance reasons I need to use arrays to store data. I implemented this in a generic fashion like this (see this answer):
import java.lang.reflect.Array;
public class SimpleArray<T> {
private T[] data;
@SuppressWarnings("unchecked")
public SimpleArray(Class<T> cls, int size) {
this.data = (T[]) Array.newInstance(cls, size);
}
public T get(int i) {
return data[i];
}
}
The problem is that I need the involved Class<?>
es. However, I might have a more complex class hierarchy containing generics:
public class Outer<T> {
public class Inner {
}
}
I would like to initialize the array as I would with an ordinary class:
SimpleArray<Integer> intArray = new SimpleArray<>(Integer.class, 10);
intArray.get(0);
SimpleArray<Outer<Integer>> outerArray;
// how to initialize this?
SimpleArray<Outer<String>.Inner> innerArray;
// how to initialize this?
I read the post on how to (not) get the Class
of something generic (here) but the bottom-line seems to be that everything is type-safety related syntactic sugar.
My question is the following: How can I create instances of the SimpleArray
classes above while avoiding as much ugliness as possible?
Upvotes: 0
Views: 1243
Reputation: 122449
There are two issues here.
Do you really need to pass in a Class
? In this case, no. Your class does not actually need to know the element type at runtime to do its job. For example, you can just do:
public class SimpleArray<T> {
private Object[] data;
public SimpleArray(int size) {
this.data = new Object[size];
}
@SuppressWarnings("unchecked")
public T get(int i) {
return (T)data[i];
}
}
If you really needed a Class<T>
, how would you get one? Well, first you need to ask yourself, what are you going to use this for? There will never be a "true" Class<T>
for a non-reifiable type T
because with a Class<T>
you can do things like .isInstance()
to check whether something is an instance of T
at runtime; but of course it's not possible to check instance-of with non-reifiable types at runtime.
In this case, you're only going to pass it to Array.newInstance()
, and Array.newInstance()
uses the raw type anyway (it does not care about the compile-time type of the Class
parameter -- the parameter type is Class<?>
-- it only uses the runtime value of the Class
object), it is sufficient to simply coerce a Class
object representing the raw type to the appropriately-parameterized Class
type:
(Class<Outer<Integer>>)(Class<?>)Outer.class
Upvotes: 1
Reputation: 37645
You seem to be trying to make a class that wraps an array and provides a method to get
elements. The class Arrays.ArrayList
does exactly that already, so there is no need to reinvent the wheel. It works as follows:
List<String> list = Arrays.asList(new String[30]);
list.set(3, "foo");
System.out.println(list.get(3));
You can't use Arrays.asList
to produce a List<T>
if the type T
is generic without suppressing a warning because it is not possible to create a generic array. You can write a helper method to do this for you though.
@SuppressWarnings("unchecked")
public static <T> List<T> newArray(int size) {
return (List<T>) Arrays.asList(new Object[size]);
}
You can use the returned List
to get and set elements without having to cast, even if the type T
is generic. For example:
List<List<String>> list = newArray(30);
list.set(4, Arrays.asList("A", "B", "C"));
System.out.println(list.get(4));
Upvotes: 1