简体   繁体   English

Java 8 ArrayList 初始容量坏了?

[英]Java 8 ArrayList initial capacity broken?

Today I was looking in cloning an ArrayList when I ran in a weird problem.今天,当我遇到一个奇怪的问题时,我正在考虑克隆一个 ArrayList。 I read this answer and tried that.我阅读了这个答案并尝试过。 However, I received an ArrayOutOfBounds exception.但是,我收到了一个 ArrayOutOfBounds 异常。 So I looked a bit more into it, and appearently the ArrayList<>(int size) is not working?所以我仔细研究了一下,似乎 ArrayList<>(int size) 不起作用?
Is this a known problem?这是一个已知问题吗?

Test class:测试类:

import java.util.ArrayList;
import java.util.List;

import org.junit.Test;

public class ArrayListTest {
    @Test
    public void test() {
        List<String> lista = new ArrayList<>();
        lista.add("a");
        List<String> listb = new ArrayList<>(lista.size());
        System.out.println("Size of lista: " + lista.size());
        System.out.println("Size of listb: " + listb.size());
    }
}

Troubled class:疑难班:

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import org.junit.Test;

public class ArrayListTest2 {
    @Test
    public void test() {
        List<String> lista = new ArrayList<>();
        lista.add("a");
        List<String> listb = new ArrayList<>(lista.size());
        Collections.copy(listb, lista);
        System.out.println("Lista: " + lista);
        System.out.println("Listb: " + listb);
    }
}

Which results in:结果是:

java.lang.IndexOutOfBoundsException: Source does not fit in dest java.lang.IndexOutOfBoundsException:源不适合目标
at java.util.Collections.copy(Collections.java:556)在 java.util.Collections.copy(Collections.java:556)
at ArrayListTest2.test(ArrayListTest2.java:13)在 ArrayListTest2.test(ArrayListTest2.java:13)

Any ideas?有任何想法吗?

This is really a problem with the documentation of Collections.copy() .这确实是Collections.copy()文档的问题。 Its JDK 8 documentation says:它的JDK 8 文档说:

The destination list must be at least as long as the source list.目标列表必须至少与源列表一样长。 If it is longer, the remaining elements in the destination list are unaffected.如果它更长,则目标列表中的其余元素不受影响。

This uses the terms "long" and "longer" which seem to refer to the length of a list.这使用了术语“长”和“更长”,它们似乎指的是列表的长度 However, if you look at the List specification, there is no definition of length -- there are however definitions for size and, in ArrayList , for capacity .但是,如果您查看List规范,则没有长度的定义——但是有size 的定义,在ArrayList中有容量的定义 It's unclear whether Collections.copy() is defined in terms of the size or capacity of the lists.目前还不清楚Collections.copy()是根据列表的大小还是容量来定义的。

In fact, Collections.copy() should be defined in terms the size of the lists.事实上, Collections.copy()应该根据列表的大小来定义。 The JDK 9 specification of Collections.copy() has been modified to read: Collections.copy()JDK 9 规范已修改为:

The destination list's size must be greater than or equal to the source list's size.目标列表的大小必须大于或等于源列表的大小。 If it is greater, the remaining elements in the destination list are unaffected.如果它更大,则目标列表中的其余元素不受影响。

The arg to the ArrayList constructor sets its initial capacity , not its size . ArrayList构造函数的 arg 设置它的初始容量,而不是它的大小 The size is the number of elements that are currently present in the list.大小是列表中当前存在的元素数。 Collections.copy() requires the destination list's size to be greater or euqal to the source's size. Collections.copy()要求目标列表的大小大于或等于源的大小。 That's why you get IndexOutOfBoundsException when you try to copy a list of size 1 into a list of size 0.这就是为什么当您尝试将大小为 1 的列表复制到大小为 0 的列表时会得到IndexOutOfBoundsException的原因。

If the target List is too small.I will throw IndexOutOfBoundsException.如果目标列表太小,我会抛出IndexOutOfBoundsException。

import java.util.*;

public class CollectionsDemo {
   public static void main(String args[]) {
      // create two lists    
      List<String> srclst = new ArrayList<String>(5);
      List<String> destlst = new ArrayList<String>(10);

      // populate two lists
      srclst.add("a");
      srclst.add("b");
      srclst.add("d");

      destlst.add("e");
      destlst.add("f");
      destlst.add("g");


      // copy into dest list
      Collections.copy(destlst, srclst);            

      System.out.println("Value of source list: "+srclst);
      System.out.println("Value of destination list: "+destlst);
   }    

I think there is a problem with your understanding of the initialCapacity .我认为您对initialCapacity的理解存在问题。 Like when you initialize an array of primitive that gets filled with 'null' values, nothing as such happens during the initialization of an ArrayList .就像当你初始化一个用“空”值填充的基元数组时,在ArrayList的初始化过程中不会发生这样的事情。 By setting an initialCapacity of n , all you are doing is letting the compiler know that it should allocate enough memory for n objects.通过将initialCapacity设置为n ,您所做的就是让编译器知道它应该为n对象分配足够的内存。 Please note, that even though memory has been allocated, the size of the list is still 0 since there are no elements inside it.请注意,即使已分配内存,列表的大小仍为 0,因为其中没有元素。

About the copy() .关于copy() You are trying to copy lista into a list with an initial capacity of lista.size() = 0 .您正在尝试将lista复制到初始容量为lista.size() = 0 Doesn't something seem amiss there?那里似乎没有什么不对劲的地方吗?

This confusion may be warranted to the fact that the documentation simply doesn't mention the word size , yet that is the key factor here.这种混淆可能是因为文档根本没有提到字size ,但这是这里的关键因素。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM