3

我正在尝试使用 Java Lists 创建一个延迟加载方法,该方法接受索引,将元素添加到 List 直到索引有效,然后返回该索引处的值。

例如,假设我有一个这样的列表[0, 1, 2, 3]。如果我用它调用我的方法并传入索引 1,它应该返回 1 而不会以任何方式更改 List。如果我用它调用我的方法并传入索引 5,它应该返回 0(默认整数值)并且我的 List 现在应该看起来像这样[0, 1, 2, 3, 0, 0]

一开始实现起来似乎很简单,但是当我尝试传入像List<List<String>>. 我知道你不能实例化一个列表,所以我尝试制作一个 ArrayList,但它不起作用。

这是我的方法的当前化身

protected <T> T getOrCreateAt(int index, List<T> list, Class<T> elementClass) {
    while (list.size() < index + 1) {
        try {
            list.add(elementClass.newInstance());
        } catch (InstantiationException e) {
            e.printStackTrace();
            System.exit(1);
        } catch (IllegalAccessException e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    return list.get(index);
}

这是我称之为的一个地方

List<List<String>> solutionText = new ArrayList<List<String>>();

for (Node node : solution) {
    List<String> row = getOrCreateAt(node.rowNo, solutionText, ArrayList.class);
    getOrCreateAt(node.colNo, row, String.class);
    row.set(node.colNo, String.valueOf(node.cellNo));
}

对 getOrCreateAt 的第二次调用有效,但第一次没有编译。

如何让我的延迟加载方法在接口和抽象类上工作?

4

4 回答 4

3

我理解这个问题的答案意味着这不能通过简单的方式来完成。一个有点不满意的解决方案:使参数elementClass非参数化:

static <T> T getOrCreateAt(int index, List<T> list, Class<?> elementClass) {
    while (list.size() < index + 1) {
        try {
            list.add((T) elementClass.newInstance());
            // ...

您将在演员表上收到编译器警告(未经检查的演员表)。事实上,不幸的是,你会以这种方式失去类型安全性。

于 2012-07-22T22:11:19.873 回答
2

我过去遵循的一种类似工厂的行为是通过匿名类完成的。

interface Factory<T> {
    T newInstance() throws InstantiationException, IllegalAccessException;
}

然后是您需要的实现

Factory<List<String>> arrayListFactory = new Factory<List<String>>() {
    @Override
    public List<String> newInstance() throws InstantiationException, IllegalAccessException {
        return new ArrayList<String>();
    }
};
Factory<String> stringFactory = new Factory<String>() {
    @Override
    public String newInstance() throws InstantiationException, IllegalAccessException {
        return String.class.newInstance();
    }
};

当然改变你的方法来接受工厂的东西而不是一个类。

protected static <T> T getOrCreateAt(int index, List<T> list, Factory<T> factory) {
    while (list.size() < index + 1) {
        try {
            list.add(factory.newInstance());

所以用法看起来像

for (Node node : solution) {
    List<String> row = TestThing.getOrCreateAt(node.rowNo, solutionText, arrayListFactory);
    getOrCreateAt(node.colNo, row, stringFactory);
    row.set(node.colNo, String.valueOf(node.cellNo));
}

如果我不需要在一个文件之外使用它,我可能会将它们全部作为内部成员粘贴在该源文件中。

于 2012-07-23T22:34:38.373 回答
0

你有没有尝试过

protected <T> T getOrCreateAt(int index, List<T> list, Class<? extends T> elementClass) {
    // ...
}

List<String> row = getOrCreateAt(node.rowNo, solutionText, ( Class< ArrayList< String > > )solutionText.getClass());

? ArrayList< String >是 的子类List< String >,所以Class< ArrayList >Class< ? extends List >(但不是Class< List >)的子类。强制转换和getClass()调用是必要的,因为ArrayList.class不是Class< ? extends List< String > >.

于 2012-07-23T03:36:10.237 回答
0

子类 ArrayList(记住泛型)并覆盖 set 方法以获取您描述的行为。此代码显示了 if nullis 如何成为未分配元素的值。

public T set(int index, T arg1) {
    while (index >= size()) {
        add(null);
    }
    return super.set(index, arg1);
}

new然后,您可以通过在分配列表时使用不同的方法来根据需要使用新行为的列表。

我猜你可以在一个完整的代码中做到这一点。

于 2012-07-23T22:42:33.180 回答