出于性能原因,我需要使用数组来存储数据。我以这样的通用方式实现了这一点(参见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];
}
}
问题是我需要涉及的Class<?>
es。但是,我可能有一个包含泛型的更复杂的类层次结构:
public class Outer<T> {
public class Inner {
}
}
我想像普通类一样初始化数组:
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?
我阅读了关于如何(不)获取通用(here)的Class
的帖子,但底线似乎是所有内容都与类型安全相关的语法糖。
我的问题如下:我如何创建上述SimpleArray
类的实例,同时避免尽可能多的丑陋?
答案 0 :(得分:1)
您似乎正在尝试创建一个包装数组的类,并为get
元素提供方法。班级Arrays.ArrayList
已经完成了,所以没有必要重新发明轮子。它的工作原理如下:
List<String> list = Arrays.asList(new String[30]);
list.set(3, "foo");
System.out.println(list.get(3));
如果类型Arrays.asList
是通用的,而不抑制警告,则无法使用List<T>
生成T
,因为无法创建通用数组。您可以编写辅助方法来为您执行此操作。
@SuppressWarnings("unchecked")
public static <T> List<T> newArray(int size) {
return (List<T>) Arrays.asList(new Object[size]);
}
即使类型List
是通用的,您也可以使用返回的T
来获取和设置元素而无需强制转换。例如:
List<List<String>> list = newArray(30);
list.set(4, Arrays.asList("A", "B", "C"));
System.out.println(list.get(4));
答案 1 :(得分:1)
这里有两个问题。
你真的需要传递Class
吗?在这种情况下,没有。您的类实际上不需要在运行时知道元素类型来完成它的工作。例如,您可以这样做:
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];
}
}
如果你真的需要一个Class<T>
,你会怎么得到一个?那么,首先你需要问问自己,你打算用它做什么?对于不可重复的类型Class<T>
,永远不会有“真实”T
,因为使用Class<T>
,您可以执行.isInstance()
之类的操作来检查某些内容是否为T
在运行时;但是当然不可能在运行时检查带有不可再生类型的实例。
在这种情况下,您只需将其传递给Array.newInstance()
,而Array.newInstance()
仍然使用原始类型(它不关心{{1}的编译时类型参数 - 参数类型是Class
- 它只使用Class<?>
对象的运行时值,只需将表示原始类型的Class
对象强制转换为适当参数化的Class
类型:
Class