通用的复杂类型数组

时间:2015-09-05 21:59:55

标签: java arrays generics

出于性能原因,我需要使用数组来存储数据。我以这样的通用方式实现了这一点(参见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类的实例,同时避免尽可能多的丑陋?

2 个答案:

答案 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)

这里有两个问题。

  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];
        }
    }
    
  2. 如果你真的需要一个Class<T>,你会怎么得到一个?那么,首先你需要问问自己,你打算用它做什么?对于不可重复的类型Class<T>,永远不会有“真实”T,因为使用Class<T>,您可以执行.isInstance()之类的操作来检查某些内容是否为T在运行时;但是当然不可能在运行时检查带有不可再生类型的实例。

    在这种情况下,您只需将其传递给Array.newInstance(),而Array.newInstance()仍然使用原始类型(它不关心{{1}的编译时类型参数 - 参数类型是Class - 它只使用Class<?>对象的运行时值,只需将表示原始类型的Class对象强制转换为适当参数化的Class类型:

    Class