Java 循环 ArrayList(扩展 ArrayList)
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18659792/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Circular ArrayList (extending ArrayList)
提问by Karlovsky120
So my program has a need of a type of circular ArrayList.
所以我的程序需要一种循环ArrayList。
Only circular thing about it has to be the get(int index) method, this is the original:
关于它的唯一循环必须是 get(int index) 方法,这是原始的:
/**
* 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);
}
If index is -1 it should get the element with index ArrayList.size()-1 and if index is ArrayList.size(), it should get the element with index 0.
如果 index 为 -1,则应获取索引为 ArrayList.size()-1 的元素,如果 index 为 ArrayList.size(),则应获取索引为 0 的元素。
Simplest way of achieveing this which came to my mind is simply extending ArrayList from the java.util package and just overriding the get(int index) so it does not throw IndexOutOfBoundsException for the two indexes above, but change them to what I want. It would throw IndexOutOfBoundsException for any other index that is out of bounds.
我想到的实现这一点的最简单方法是简单地从 java.util 包扩展 ArrayList 并覆盖 get(int index) 因此它不会为上述两个索引抛出 IndexOutOfBoundsException,而是将它们更改为我想要的。对于超出范围的任何其他索引,它会抛出 IndexOutOfBoundsException。
However, since elementData(index) access a
然而,由于 elementData(index) 访问一个
private transient Object[] elementData;
I cannot make it work, because my class doesn't see it since it's private.
我不能让它工作,因为我的班级看不到它,因为它是私人的。
Also, I don't want to use any external libraries for this, simply because I think there are none that suit my needs, since I don't want a real circularArray, but only a part of it's functionality, rest of it being of the regular ArrayList.
另外,我不想为此使用任何外部库,仅仅因为我认为没有适合我的需求,因为我不想要真正的circularArray,而只是它的一部分功能,其余部分是常规的 ArrayList。
So I have two questions:
所以我有两个问题:
How can I make this work? Is there a way to do it without copying the whole ArrayList class along with AbstractCollection, Collection and Iterable into my program? That seems like bad design even to me.
我怎样才能使这项工作?有没有办法在不将整个 ArrayList 类以及 AbstractCollection、Collection 和 Iterable 复制到我的程序中的情况下做到这一点?即使对我来说,这似乎也是糟糕的设计。
If I can somehow make it work, is there anything else I should watch for? If I make the changes described above, would that change the behaviour of the class only the way I want it to, or could there be any other undesired behaviour changes?
如果我能以某种方式使它工作,还有什么我应该注意的吗?如果我进行上述更改,是否会仅按照我希望的方式更改类的行为,还是会发生任何其他不希望的行为更改?
EDIT:Thanks for the answer, here's what I've done:
编辑:感谢您的回答,这是我所做的:
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);
}
}
It will wrap around the ArrayList, but only by one. I want it to throw an exception if I try to access any other element but the first and the last with anything except their regular ArrayList indexes.
它将环绕 ArrayList,但只有一个。如果我尝试访问除第一个和最后一个元素以外的任何其他元素,但它们的常规 ArrayList 索引除外,我希望它抛出异常。
采纳答案by HerrB
Can't you derive from ArrayList and override the the get(int index) method along those lines:
您不能从 ArrayList 派生并沿这些行覆盖 get(int index) 方法:
@Override
public E get(int index)
{
if(index < 0)
index = index + size();
return super.get(index);
}
What am I missing?
我错过了什么?
Note that this implementation would not fold arbitrary indices into your valid index range but only allow you to properly address your list from both the left and right sides (with positive and negative indices respectively, a bit like in Python).
请注意,此实现不会将任意索引折叠到您的有效索引范围中,而只会允许您从左侧和右侧正确处理您的列表(分别使用正索引和负索引,有点像在 Python 中)。
回答by ppeterka
What you described is basically getting the modulus of the index you want, and accessing that element in a list.
您所描述的基本上是获取所需索引的模数,并访问列表中的该元素。
You could do the following with composition over inheritance:
您可以使用组合而不是继承来执行以下操作:
- Create a wrapper class for the interface
List<T>
, let's call it ListWrapper now- add a constructor accepting instance of List
- let the List instance be protected, and name it to
wrapped
- Extend the wrapper class
- 为接口创建一个包装类,
List<T>
现在我们称之为 ListWrapper- 添加一个接受 List 实例的构造函数
- 让 List 实例受到保护,并将其命名为
wrapped
- 扩展包装类
Why do all this crap?This is implementation agnostic. One day, you might want to use this convenience on another implementation. Then you'll have to duplicate code, and hell begins. If you need a 3rd implementation too, and then add just one tiny bit of new functionality, you are doomed.
为什么要做这些废话?这是实现不可知的。有一天,您可能希望在另一个实现中使用这种便利。然后你将不得不复制代码,地狱开始了。如果您还需要第三个实现,然后只添加一点点新功能,那您就完蛋了。
With a wrapper class in between:
中间有一个包装类:
- you can have all classes implementing the List interface to have your own functinality
- you'll be able to change the wrapper class in one place
- you'll be able to add new functionality in one place.
- 您可以让所有实现 List 接口的类拥有自己的功能
- 您将能够在一处更改包装器类
- 您将能够在一处添加新功能。
Remember, we are writing programs that will have to be maintainable!
请记住,我们正在编写必须可维护的程序!
Wrapper class
包装类
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
}
Now the real new class
现在是真正的新班级
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);
}
}
BEWARE
谨防
- this however is not safe for multithreaded environments!
- be careful about all the instances of the original list - if you mutate that, the ModList instance will mutate too
- 然而,这对于多线程环境是不安全的!
- 小心原始列表的所有实例 - 如果你改变它,ModList 实例也会改变
回答by Ghostkeeper
You can extend the ArrayList class to change the functionality of the get
method, without the need to access the elementData
field:
您可以扩展 ArrayList 类来更改该get
方法的功能,而无需访问该elementData
字段:
public class CircularList<E> extends ArrayList<E> {
@Override
public E get(int index) {
return super.get(index % size());
}
}
The super.get
method will still perform the range checks (but those will never fail).
该super.get
方法仍将执行范围检查(但这些检查永远不会失败)。
You should be aware that doing this can give the ArrayList unstable indices. If the size of the list changes, then all indices outside of the normal range will change. For instance, if you have a list ['a','b','c','d','e']
, then get(7)
will return c
. If you then do add('f')
, then get(7)
will suddenly return b
, because get
will now be working modulo 6 instead of modulo 5.
您应该知道这样做会导致 ArrayList 索引不稳定。如果列表的大小发生变化,那么所有超出正常范围的索引都会发生变化。例如,如果您有一个 list ['a','b','c','d','e']
,get(7)
则将返回c
。如果你这样做add('f')
,那么get(7)
会突然返回b
,因为get
现在将工作模 6 而不是模 5。
回答by red1kissi
Does anyone know this AbstractList extension : com.sun.appserv.management.util.misc.CircularList<T>
. Take a look at it. It's GlassFish java.net community solution. It should be powerful because it's used in Thread Scheduling inside GlassFish Container.
有谁知道这个 AbstractList 扩展名:com.sun.appserv.management.util.misc.CircularList<T>
。看一看。它是 GlassFish java.net 社区解决方案。它应该很强大,因为它用于 GlassFish Container 内的线程调度。
回答by Stuart Clark
The chosen answer doesn't handle the case where the index is a negative number with a very large magnitude and the size of the list is small i.e.
选择的答案不处理索引是一个非常大的负数并且列表的大小很小的情况,即
Size => 10 Index => -1000000
大小 => 10 索引 => -1000000
Here is an implementation that should handle all sizes and indexes
这是一个应该处理所有大小和索引的实现
import java.util.ArrayList;
import java.util.Collection;
/**
* A list the loops round to the first element when {@link CircularList#get(int)} is called with an
* index that is greater than the max index of the list and vice versa.
*
* @author Stuart Clark
*/
public class CircularList<E> extends ArrayList<E> {
public CircularList() {
super();
}
public CircularList(int initialCapacity) {
super(initialCapacity);
}
public CircularList(Collection<? extends E> c) {
super(c);
}
@Override
public E get(int index) {
if (isEmpty()) {
throw new IndexOutOfBoundsException("The list is empty");
}
while (index < 0) {
index = size() + index;
}
return super.get(index % size());
}
}