首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >圆形ArrayList (扩展ArrayList)

圆形ArrayList (扩展ArrayList)
EN

Stack Overflow用户
提问于 2013-09-06 14:08:14
回答 5查看 61.9K关注 0票数 20

所以我的程序需要一种循环的ArrayList。

有关它的唯一循环内容必须是get( index)方法,这是原始的:

代码语言:javascript
复制
    /**
     * Returns the element at the specified position in this list.
     *
     * @param  index index of the element to return
     * @return the element at the specified position in this list
     * @throws IndexOutOfBoundsException {@inheritDoc}
     */ 
    public E get(int index) {
        rangeCheck(index);

        return elementData(index);
    }

如果索引是-1,它应该得到索引ArrayList.size()-1的元素,如果索引是ArrayList.size(),则应该得到索引0的元素。

实现这一目标的最简单的方法就是从ArrayList包中扩展java.util,并且只是覆盖get(int索引),这样它就不会为上面的两个索引抛出IndexOutOfBoundsException,而是将它们更改为我想要的。它将为任何超出界限的其他索引抛出IndexOutOfBoundsException。

但是,由于elementData(索引)访问

代码语言:javascript
复制
private transient Object[] elementData;

我不能让它工作,因为我的课没有看到它,因为它是私人的。

而且,我不想为此使用任何外部库,仅仅因为我认为没有一个适合我的需要,因为我不想要一个真正的circularArray,而只是它的一部分功能,其余的部分属于常规的ArrayList。

所以我有两个问题:

我怎么才能把这事做好?有没有办法不将整个ArrayList类与AbstractCollection、Collection和Iterable一起复制到我的程序中呢?对我来说,这似乎是个糟糕的设计。

如果我能让它成功的话,还有什么值得我注意的吗?如果我做了上面描述的更改,这会改变类的行为方式吗?还是会有任何其他不想要的行为改变?

编辑:,谢谢你的回答,下面是我所做的:

代码语言:javascript
复制
import java.util.ArrayList;

public class CircularArrayList<E> extends ArrayList<E>
{
    private static final long serialVersionUID = 1L;

    public E get(int index)
    {
        if (index == -1)
        {
            index = size()-1;
        }

        else if (index == size())
        {
            index = 0;
        }

        return super.get(index);
    }
}

它将包围ArrayList,但只有一个。如果我尝试访问除第一个和最后一个元素之外的任何其他元素,除了它们的常规ArrayList索引之外,我希望它抛出一个异常。

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2013-09-06 14:15:46

您不能从ArrayList派生并按照以下代码重写get( index)方法:

代码语言:javascript
复制
@Override
public E get(int index)
{
    if(index < 0)
        index = index + size();

    return super.get(index);
}

我遗漏了什么?

请注意,此实现不会将任意索引折叠到有效的索引范围中,而只允许您从左侧和右侧正确地处理列表(分别带有正索引和负索引,有点像Python中的索引)。

票数 12
EN

Stack Overflow用户

发布于 2013-09-06 14:16:52

您可以扩展ArrayList类以更改get方法的功能,而无需访问elementData字段:

代码语言:javascript
复制
public class CircularList<E> extends ArrayList<E> {

    @Override
    public E get(int index) {
        return super.get(index % size());
    }
}

super.get方法仍将执行范围检查(但这些检查永远不会失败)。

您应该知道,这样做会给出ArrayList不稳定的索引。如果列表的大小发生变化,则正常范围以外的所有索引都将发生变化。例如,如果您有一个list ['a','b','c','d','e'],那么get(7)将返回c。如果然后执行add('f'),那么get(7)将突然返回b,因为get现在将使用模块化6而不是模块化5。

票数 33
EN

Stack Overflow用户

发布于 2013-09-06 14:12:55

您所描述的基本上是获取所需索引的模数,并在列表中访问该元素。

您可以使用组合而不是继承来完成以下操作:

  • 为接口List<T>创建包装类,让我们称之为ListWrapper now
    • 添加一个接受列表实例的构造函数
    • 让列表实例受到保护,并将其命名为wrapped

  • 扩展包装器类

为什么做这些废话?,这是与实现无关的。有一天,您可能希望在另一个实现上使用这种方便。然后你将不得不重复代码,然后地狱开始了。如果您也需要第三个实现,然后只添加一个小小的新功能,您就注定要失败。

在中间有一个包装类:

  • 您可以让实现列表接口的所有类具有自己的功能。
  • 您将能够在一个地方更改包装类
  • 您将能够在一个地方添加新功能。

记住,我们正在编写的程序必须是可维护的!

包装器类

代码语言:javascript
复制
public abstract class ListWrapper<T> implements List<T> {
    protected final List<T> wrapped;

    public ListWrapper(List<T> wrapped) {
        this.wrapped = wrapped;
    }

    public T get(int index) {
        return wrapped.get(index);
    }

    //omitting the other wrapper methods, for sake of brevity.
    //Note: you still have to add them.
    // Eclipse: Source menu, Generate Delegate methods does the trick nicely
}

现在是真正的新类

代码语言:javascript
复制
public class ModList<T> extends ListWrapper<T> {

    public ModList(List<T> list) {
        super(list);
    }

    @Override
    public T get(int index) {
        int listSize = wrapped.size();
        int indexToGet = index % listSize;

        //this might happen to be negative
        indexToGet = (indexToGet < 0) ? indexToGet+listSize : indexToGet;
        return wrapped.get(indexToGet);
    }

}

小心

  • 但是,这对于多线程环境是不安全的!
  • 小心原始列表的所有实例--如果您改变了它,ModList实例也会发生变异。
票数 11
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/18659792

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档