如何返回多个类型的对象

时间:2015-04-20 23:01:54

标签: java list collections random-access

让我们举一个例子来简化它。我构建了一个构造函数采用integerList<Integer>的列表。我的列表将包含给定列表的所有元素乘以integer。我的列表不存储新元素,而是动态计算它们:

class MyList extends AbstractList<Integer> implements RandomAccess {
    private final int multiplier;
    private final List<Integer> list;

    public MyList(int multiplier, List<Integer> list) {
        this.multiplier = multiplier;
        this.list = list;
    }

    @Override
    public Integer get(int index) {
        return list.get(index) * multiplier;
    }

    @Override
    public int size() {
        return list.size();
    }
}

然后,我们可以使用new MyList(3, list)致电list = [0, 1, 2, 3]以获取[0, 3, 6, 9]

我想限制开发人员给MyList构造函数一个也是RandomAccess的列表,以确保他不会破坏性能。

我尝试用以下内容更改构造函数:

public <E extends List<Integer> & RandomAccess> MyList(int multiplier, E list)

MyList不是问题,但现在我们无法在不使用List<Integer>RandomAccess ArrayList<Integer>的实现的情况下调用构造函数。因此,拥有此列表的人:List<Integer> list = new ArrayList<>();无法new MyList(3, list);(因为它是使用List<Integer>而不是ArrayList<Integer>声明的。)

我的另一个解决方案就是这个:

public MyList(int multiplier, List<Integer> list) {
        if(!(list instanceof RandomAccess)) {
            // Do something like log or throw exception
        }
        this.multiplier = multiplier;
        this.list = list;
    }

但是现在我无法在编译时检查列表是否实现了RandomAccess,我需要使用instanceof并且我讨厌这样做。

我很确定有更好的方法,但它是什么?

3 个答案:

答案 0 :(得分:1)

您可以采用Collections.unmodifiableList使用的解决方案。而不是公共构造函数,有一个静态方法返回两个实现之一,一个实现RandomAccess,另一个不实现。

以下是Collections.unmodifiableList的代码。

public static <T> List<T> unmodifiableList(List<? extends T> list) {
    return (list instanceof RandomAccess ?
            new UnmodifiableRandomAccessList<>(list) :
            new UnmodifiableList<>(list));
}

我知道你说你不喜欢使用instanceof。我也不是,但有时这是最好的事情。

请注意使用构造函数的解决方案

public <E extends List<Integer> & RandomAccess> MyList(int multiplier, E list)

不仅仅是丑陋的,因为它迫使程序员施放(例如到ArrayList),但它实际上并不起作用。例如,如果listCollections$UnmodifiableRandomAccessList的实例,则甚至无法将其强制转换为同时实现ListRandomAccess的类型,因为Collections$UnmodifiableRandomAccessList是私人的。

答案 1 :(得分:1)

我建议使用instanceof。事实上,这正是RandomAccess文档建议的内容:

  

鼓励通用列表算法检查给定列表   是应用算法之前的此接口的实例   如果将其应用于顺序,则会提供较差的性能   访问列表,并在必要时改变其行为以保证   可接受的表现。

您的构造函数可能有两个实现。如果RandomAccess已实施,则会存储对List的引用,否则会创建新的ArrayList并将所有元素复制到其中:

class MyList {
    private final int multiplier;
    private final List<Integer> list;

    public MyList(int multiplier, List<Integer> list) {
        this.multiplier = multiplier;
        if (list instanceof RandomAccess)
            this.list = list;
        else
            this.list = new ArrayList<>(list);
    }

    public int get(int index) {
        return multiplier * list.get(index);
    }
}

答案 2 :(得分:0)

如果你的类需要一个随机访问列表,那么你的类应该处理它而不是将你的类的需求推送到调用者。此外,在构造函数中进行乘法会更简单 - 您必须在某个时刻执行此操作,但提前执行意味着您可以丢弃大量代码:

class MyList extends ArrayList<Integer> {

    public MyList(int multiplier, List<Integer> list) {
        for (Integer i : list)
            add(i * multiplier);
    }
}

这就是你所需要的,它更安全:通过你的推荐,你的列表和调用者都有对列表的引用。如果在调用构造函数后调用更改了列表,则使用相乘列表的其他代码将意外地看到列表中的值发生更改。