在Java中定义固定大小的列表

时间:2011-03-05 22:17:24

标签: java list collections

是否可以定义固定大小为100的列表?如果不是为什么在Java中没有这个?

13 个答案:

答案 0 :(得分:34)

如果内存服务,这应该这样做:

List<MyType> fixed = Arrays.asList(new MyType[100]);

答案 1 :(得分:27)

您的问题是错误的,或者您对Java List的心理模型不正确。


Java列表是对象的集合......列表的元素。列表的大小是该列表中元素的数量。如果您希望修复该大小,则意味着您无法添加或删除元素,因为添加或删除元素会违反“固定大小”约束。

实现“固定大小”列表的最简单方法(如果这真的是你想要的!)是将元素放入数组中,然后Arrays.asList(array)创建列表包装器。包装器允许您执行getset等操作,但addremove操作将抛出异常。

如果要为现有列表创建固定大小的包装器,则可以使用Apache commons FixedSizeList类。但请注意,此包装器无法阻止其他更改原始列表大小的内容,如果发生这种情况,则包装列表可能会反映这些更改。 (IMO,FixedSizeList的javadoc很糟糕。它没有尝试记录更改包装列表时类的行为。你需要阅读源代码......并希望它们不会改变当你不注意时的行为。)


另一方面,如果你真的想要一个对其大小有固定限制(或限制)的列表类型,那么你需要创建自己的List类来实现它。例如,您可以创建一个包装类,该类在各种add / addAllremove / removeAll / retainAll操作中实现相关检查。 (如果支持它们,则使用迭代器remove方法。)

那么为什么Java Collections框架没有实现这些呢?这就是为什么我这么认为:

  1. 需要这种情况的用例很少见。
  2. 在需要这种情况的用例中,当操作试图打破限制时,对于该怎么做有不同的要求;例如抛出异常,忽略操作,丢弃一些其他元素来腾出空间。
  3. 带有限制的列表实现可能对辅助方法有问题;例如Collections.sort

答案 2 :(得分:17)

Commons library提供内置FixedSizeList,不支持addremoveclear方法(但允许使用set方法,因为它不会修改List的大小。换句话说,如果您尝试调用其中一种方法,则列表仍保持相同的大小。

要创建固定尺寸列表,只需致电

List<YourType> fixed = FixedSizeList.decorate(Arrays.asList(new YourType[100]));

如果您想要指定列表的不可修改的视图,或者对内部列表的只读访问,则可以使用unmodifiableList

List<YourType> unmodifiable = java.util.Collections.unmodifiableList(internalList);

答案 3 :(得分:13)

是。您可以将java数组传递给Arrays.asList(Object[])

List<String> fixedSizeList = Arrays.asList(new String[100]);

您不能将新的字符串插入fixedSizeList(它已经有100个元素)。您只能设置如下值:

fixedSizeList.set(7, "new value");

这样你有一个固定的大小列表。这个东西就像一个数组,我想不出一个使用它的好理由。我很想知道为什么你希望固定大小的集合成为一个列表,而不是仅使用数组。

答案 4 :(得分:8)

通常,固定大小列表的替代方法是Java数组。默认情况下,列表允许在Java中增长/缩小。但是,这并不意味着您不能拥有固定大小的列表。您需要做一些工作并创建自定义实现。

您可以使用clear,add和remove方法的自定义实现来扩展ArrayList

e.g。

import java.util.ArrayList;

public class FixedSizeList<T> extends ArrayList<T> {

    public FixedSizeList(int capacity) {
        super(capacity);
        for (int i = 0; i < capacity; i++) {
            super.add(null);
        }
    }

    public FixedSizeList(T[] initialElements) {
        super(initialElements.length);
        for (T loopElement : initialElements) {
            super.add(loopElement);
        }
    }

    @Override
    public void clear() {
        throw new UnsupportedOperationException("Elements may not be cleared from a fixed size List.");
    }

    @Override
    public boolean add(T o) {
        throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
    }

    @Override
    public void add(int index, T element) {
        throw new UnsupportedOperationException("Elements may not be added to a fixed size List, use set() instead.");
    }

    @Override
    public T remove(int index) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }

    @Override
    public boolean remove(Object o) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }

    @Override
    protected void removeRange(int fromIndex, int toIndex) {
        throw new UnsupportedOperationException("Elements may not be removed from a fixed size List.");
    }
}

答案 5 :(得分:3)

创建一个大小为100的数组。如果需要List接口,请在其上调用Arrays.asList。它将返回由数组支持的固定大小的列表。

答案 6 :(得分:2)

如果您想要一些灵活性,请创建一个监视列表大小的类。

这是一个简单的例子。您需要覆盖更改列表状态的所有方法。

public class LimitedArrayList<T> extends ArrayList<T>{
    private int limit;

    public LimitedArrayList(int limit){
        this.limit = limit;
    }

    @Override
    public void add(T item){
        if (this.size() > limit)
            throw new ListTooLargeException();
        super.add(item);
    }

    // ... similarly for other methods that may add new elements ...

答案 7 :(得分:1)

您可以定义如下通用函数:

@SuppressWarnings("unchecked")
public static <T> List<T> newFixedSizeList(int size) {
    return (List<T>)Arrays.asList(new Object[size]);
}

List<String> s = newFixedSizeList(3);  // All elements are initialized to null
s.set(0, "zero");
s.add("three");  // throws java.lang.UnsupportedOperationException

答案 8 :(得分:1)

这应该很好。它永远不会超过初始大小。 toList方法将按正确的时间顺序为您提供条目。这是在groovy中完成的-但是将其正确转换为Java应该很容易。

static class FixedSizeCircularReference<T> {
    T[] entries
    FixedSizeCircularReference(int size) {
        this.entries = new Object[size] as T[]
        this.size = size
    }
    int cur = 0
    int size
    void add(T entry) {
        entries[cur++] = entry
        if (cur >= size) {
            cur = 0
        }
    }
    List<T> asList() {
        List<T> list = new ArrayList<>()
        int oldest = (cur == size - 1) ? 0 : cur
        for (int i = 0; i < this.entries.length; i++) {
            def e = this.entries[oldest + i < size ? oldest + i : oldest + i - size]
            if (e) list.add(e)
        }
        return list
    }
}

FixedSizeCircularReference<String> latestEntries = new FixedSizeCircularReference(100)
latestEntries.add('message 1') 
// .....
latestEntries.add('message 1000') 
latestEntries.asList() //Returns list of '100' messages

答案 9 :(得分:0)

如果您想使用ArrayListLinkedList,似乎答案是肯定的。尽管java中有一些类可以设置固定大小,如PriorityQueue,但ArrayList和LinkedList不能,因为这两个类没有构造函数来指定容量。

如果你想坚持使用ArrayList / LinkedList,一个简单的解决方案是每次都手动检查大小。

public void fixedAdd(List<Integer> list, int val, int size) {
    list.add(val);
    if(list.size() > size) list.remove(0);
}
在这种情况下,

LinkedList优于ArrayList。假设要添加许多值但列表大小非常小,将会有许多删除操作。原因是从ArrayList中删除的成本是O(N),但是对于LinkedList只有O(1)。

答案 10 :(得分:0)

JDK的公共java.util.List子类没有提供不属于List specification的一部分的固定大小功能。
您只能在处理非常具体的要求的Queue子类(例如ArrayBlockingQueue,例如由数组支持的有界阻塞队列)中找到它。

在Java中,List类型的代码可以根据两种情况实现:

1)固定列表大小始终是实际大小和最大大小。

听起来像是数组定义。因此,Arrays.asList()返回的是您要查找的,由指定数组支持的固定大小列表。与数组一样,您不能增加或减小其大小,而只能更改其内容。因此,不支持添加和删除操作。

例如:

Foo[] foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput);
foos.add(new Foo()); // throws an Exception
foos.remove(new Foo()); // throws an Exception

它也可以作为集合的输入,首先我们将其转换为数组:

Collection<Foo> foosInput= ...;
List<Foo> foos = Arrays.asList(foosInput.toArray(Foo[]::new)); // Java 11 way
// Or
List<Foo> foos = Arrays.asList(foosInput.stream().toArray(Foo[]::new)); // Java 8 way

2)列表内容一创建就不知道。因此,您的意思是按固定大小列出其最大大小。

您可以使用继承(extends ArrayList),但您应该更喜欢使用组合,因为它可以让您不将类与该实现的实现细节相结合,并且还提供了修饰/组成的实现的灵活性。

有了Guava Forwarding classes,您可以做到:

import com.google.common.collect.ForwardingList;

public class FixedSizeList<T> extends ForwardingList<T> {

  private final List<T> delegate;
  private final int maxSize;

  public FixedSizeList(List<T> delegate, int maxSize) {
    this.delegate = delegate;
    this.maxSize = maxSize;
  }

  @Override protected List<T> delegate() {
    return delegate;
  }

  @Override public boolean add(T element) {
    assertMaxSizeNotReached(1);
    return super.add(element);
  }

  @Override public void add(int index, T element) {
    assertMaxSizeNotReached(1);
    super.add(index, element);
  }

  @Override public boolean addAll(Collection<? extends T> collection) {
    assertMaxSizeNotReached(collection.size());
    return super.addAll(collection);
  }

  @Override public boolean addAll(int index, Collection<? extends T> elements) {
    assertMaxSizeNotReached(elements.size());
    return super.addAll(index, elements);
  }    

  private void assertMaxSizeNotReached(int size) {
    if (delegate.size() + size >= maxSize) {
      throw new RuntimeException("size max reached");
    }
  }

}

并使用它:

List<String> fixedSizeList = new FixedSizeList<>(new ArrayList<>(), 3); 
fixedSizeList.addAll(Arrays.asList("1", "2", "3"));
fixedSizeList.add("4");  // throws an Exception

请注意,对于合成,您可以将其与任何List实现一起使用:

List<String> fixedSizeList = new FixedSizeList<>(new LinkedList<>(), 3); 
//...

继承是不可能的。

答案 11 :(得分:0)

是可以的:

List<Integer> myArrayList = new ArrayList<>(100);

现在,myArrayList的初始容量为100

答案 12 :(得分:0)

根据传递给构建器的 T 元素的容器类型(Collection<T>T[]),您需要以下任一项:

  • 如果现有 Collection<T> YOUR_COLLECTION
<块引用>
Collections.unmodifiableList(new ArrayList<>(YOUR_COLLECTION));
  • 如果现有 T[] YOUR_ARRAY
<块引用>
Arrays.asList(YOUR_ARRAY);

就这么简单