- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
函数ArrayList.add()
工作得非常快。我检查了源代码,发现实现是Arrays.copyOf()
private void grow(int minCapacity) {
// overflow-conscious code
int oldCapacity = elementData.length;
int newCapacity = oldCapacity + (oldCapacity >> 1);
if (newCapacity - minCapacity < 0)
newCapacity = minCapacity;
if (newCapacity - MAX_ARRAY_SIZE > 0)
newCapacity = hugeCapacity(minCapacity);
// minCapacity is usually close to size, so this is a win:
elementData = Arrays.copyOf(elementData, newCapacity);
}
但是当我在代码中使用方法 Arrays.copyOf()
时,它变得非常慢。您只需运行以下代码即可查看:
public class TestArrayCopy {
public static void main(String[] args) {
long t = System.currentTimeMillis();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < 100000; i++) {
list.add(i, i);
}
System.out.println(System.currentTimeMillis() - t);
t = System.currentTimeMillis();
Integer[] array = new Integer[0];
for (int i = 0; i < 100000; i++) {
array = Arrays.copyOf(array, array.length +1);
array[i] = i;
}
System.out.println(System.currentTimeMillis() - t);
}
}
有什么想法吗?
最佳答案
每次添加新元素时,您的代码都会调用 copyOf()
:
因此,对于添加的每个元素,您必须做越来越多的工作来复制以前的元素。因此,如果您要添加 n
个元素,则总共必须执行 1 + 2 + 3 + ... + (n - 1) = n * (n - 1)/2 = n^2/2 - n/2 各个元素的副本。因此,您的运行时间与您添加的元素数量的平方成正比。
将此与正确的方法进行对比,正确的方法是拥有比您需要的更大的数组(这为您提供了添加更多元素而无需一直复制的空间),并将大小乘以每次需要扩展时固定因子。这要求您单独跟踪已添加的元素数量,并向用户谎报您的真实尺寸。该因子通常小于 2(Java 代码使用 1.5:int newCapacity = oldCapacity + (oldCapacity >> 1);
),但如果我们使用 2,数学会更简单:
- 初始数组大小是一些小但非零的数字,例如4,因此您可以免费添加 4 个元素(好吧,用于分配和初始化数组的成本,实际上是 4)
- 对于第五个元素,将大小加倍为 8 并复制 4 个旧元素;您现在可以再添加 4 个
- 对于第9个元素,将大小加倍为16,并复制8个旧元素;您现在可以再添加 8 个
- 依此类推:对于第 n + 1 个元素,将大小加倍为 2 * n 并复制旧的 n 元素,这为您提供了容纳 n 个元素的空间。
即使不评估复制的总和,我们也可以看到每批 n 个新元素都已经通过复制前一个 n 元素“付出了代价”元素,因此复制工作是线性的而不是二次的。事实上,
p>4 + 4 + 8 + 16 + ... + n/2 + n = 2 * n
(如果n
是2的幂)。
关于java - 为什么 Arrays.copyOf 这么慢?,我们在Stack Overflow上找到一个类似的问题:
https://stackoverflow.com/questions/53945602/
Java 10 的发布带来了新的静态工厂方法,具体来说: static List copyOf(Collection coll) static Set copyOf(Collection co
这个问题已经有答案了: How to make a deep copy of Java ArrayList [duplicate] (2 个回答) 已关闭 4 年前。 我的问题是我需要复制一个列表,但
我只想将“b”、“d”和“e”从 arr1 复制到 arr2,并在添加时动态增加 arr2 的大小。 我尝试添加一个if条件 if(!arr1[i].equals("a") && !arr1[i].
在看别人的关于copyonwritearraylist 这个类的时候,看到有人提出了关于:数组拷贝的方法arrays.copyof() 的问题,如下: 只是复制了引用地址,数组内的对象还是和旧数组一
我有无数带有自定义键和比较器的 map 。我注意到当我使用类似的代码创建 map 时 var map = TreeMap<>( someCustomComparator ); 然后我使用如下代
假设我有以下 map 定义: Map>> map = Maps.newHashMap(); map.put("a", Arrays.asList(Sets.newHashSet(1, 2, 3), S
我有以下代码: private static final ImmutableMultimap namesToAddress; public static List getAddresses(Strin
我有一个程序,如果整数的行为类似于整数堆栈,则使用数组。但是,对于数组,必须有定义数量的元素。当用户调用诸如 push() 之类的方法并超过初始数组数时,我必须将原始数组中的所有内容分配到更新后的数组
关于 Arrays.copyOf 是否会生成深拷贝或浅拷贝,似乎存在很多困惑和不同的意见([1] 和其他来源)。 此测试表明副本很深: String[] sourceArray = new Strin
我正在为类做作业,这需要我创建一个数组并根据用户的意愿添加到其中。这是我到目前为止所拥有的: public void add(Scanner stdIn) { entries = new St
为什么这个问题不是可能与 How Arrays.asList(int[]) can return List? 重复。这个问题并没有真正回答我的具体情况,因为我试图弄清楚我对 Arrays.copyOf
elementData = Arrays.copyOf(elementData, newCapacity); 给出错误: The method copyOf(Object[], int) is und
Java 并发实践的摘录/片段- @Immutable class OneValueCache{ private final BigInteger lastNumber; privat
关于 Arrays.copyOf 是否会产生深拷贝或浅拷贝似乎存在很多困惑和不同意见([1] 和其他来源)。 这个测试表明副本很深: String[] sourceArray = new String
我正在使用 Guava-05-snapshot 和 Sun 的 JDK 1.6执行此代码段的代码会爆炸: List badpasswords = Lists.newArrayList( Passwor
我想知道这个调用是否是线程安全的。例如,如果我有一组 s: Set s = new HashSet<>(); 还有两个线程A和B,线程A修改集合: for (int i = 0; i newS =
我正在尝试创建一个方法,它几乎可以将任何东西作为参数,并返回一个带有一些分隔符的值的串联字符串表示形式。 public static String getConcatenated(char delim
据我了解,我们可以使用 java.util.Arrays.copyOf复制二维数组,但是将其用于防御性复制是否安全(假设元素是不可变的)?例如 void setValues(Integer[][] a
我有一个关于函数“Arrays.copyOf()”的快速问题。 我有一个 IntArray "rows"和一个 Arraylist "listMoves"。我想创建一个行的副本并将其添加到 listM
函数ArrayList.add()工作得非常快。我检查了源代码,发现实现是Arrays.copyOf() private void grow(int minCapacity) { // ove
我是一名优秀的程序员,十分优秀!