简体   繁体   English

为什么Collections.shuffle()为我的数组失败?

[英]Why does Collections.shuffle() fail for my array?

Why does my code not work? 为什么我的代码不起作用?

package generatingInitialPopulation;

import java.util.Arrays;
import java.util.Collections;

public class TestShuffle {
    public static void main(String[] args) {
        int[] arr = new int[10];

        for (int i = 0; i < arr.length; i++) {
            arr[i] = i;
        }

        Collections.shuffle(Arrays.asList(arr));

        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + " ");
        }
    }
}

The result is: 0 1 2 3 4 5 6 7 8 9. 其结果是:0 1 2 3 4 5 6 7 8 9。

I was expecting a randomly shuffled sequence . 我期待一个随机改组的序列

Arrays.asList() can't be applied to arrays of primitive type as you expect. Arrays.asList()不能像您期望的那样应用于基本类型的数组。 When applied to int[] , Arrays.asList() produces a list of int[] s instead of list of Integer s. 当应用于int[]Arrays.asList()生成一个int[] s列表而不是Integer列表。 Therefore you shuffle a newly created list of int[] . 因此,您随机播放新创建的int[]列表。

This is a subtle behaviour of variadic arguments and generics in Java. 这是Java中可变参数和泛型的微妙行为。 Arrays.asList() is declared as Arrays.asList()声明为

public static <T> List<T> asList(T... a)

So, it can take several arguments of some type T and produce a list containing these arguments, or it can take one argument of type T[] and return a list backed by this array (that's how variadic arguments work). 因此,它可以采用某些类型T几个参数并生成包含这些参数的列表,或者它可以采用类型为T[]一个参数并返回由此数组支持的列表(这是可变参数的工作方式)。

However, the latter option works only when T is a reference type (ie not a primitive type such as int ), because only reference types may be used as type parameters in generics (and T is a type parameter). 但是,后一个选项仅在T是引用类型(即不是诸如int的基本类型)时才起作用,因为只有引用类型可以用作泛型中的类型参数(并且T是类型参数)。

So, if you pass int[] , you get T = int[] , and you code doesn't work as expected. 因此,如果传递int[] ,则得到T = int[] ,并且代码无法按预期工作。 But if you pass array of reference type (for example, Integer[] ), you get T = Integer and everything works: 但是如果传递引用类型的数组(例如, Integer[] ),则得到T = Integer并且一切正常:

Integer[] arr = new Integer[10]; 

for (int i = 0; i < arr.length; i++) { 
    arr[i] = i; 
} 

Collections.shuffle(Arrays.asList(arr)); 

for (int i = 0; i < arr.length; i++) { 
    System.out.print(arr[i] + " "); 
} 

Try adding this line of code to your test: 尝试将这行代码添加到您的测试中:

List l=Arrays.asList(arr);
System.out.println(l);

You will see you are printing out a single element List . 您将看到打印出单个元素List

Using Arrays.asList on a primitive array cause asList to treat the int[] as a single object rather than an array. 在原始数组上使用Arrays.asList会导致asListint[]视为单个对象而不是数组。 It returns a List<int[]> instead of a List<Integer> . 它返回List<int[]>而不是List<Integer> So, you are basically shuffling a single element List and so nothing really gets shuffled. 所以,你基本上是在改变单个元素List ,所以没有什么能真正被洗牌。

Notice that some of the answers already given are wrong because asList returns a List backed by the original array, nothing gets copied - all changes are reflected in the orginal array. 请注意,已经给出的一些答案是错误的,因为asList返回由原始数组支持的List,没有任何内容被复制 - 所有更改都反映在原始数组中。

That doesn't work because the call to shuffle is operating on the List returned by Arrays.asList , not on the underlying array. 这不起作用,因为对shuffle的调用是在Arrays.asList返回的List Arrays.asList ,而不是在底层数组上运行。 Thus, when you iterate over the array to print out the values, nothing has changed. 因此,当您遍历数组以打印出值时,没有任何更改。 What you want to do is save a reference to the List returned by Arrays.asList , and then print out the values of that List (rather than the values of the array) after you shuffle it. 你想要做的是保存对Arrays.asList返回的ListArrays.asList ,然后在你shuffle之后打印出该List的值(而不是数组的值)。

Store the list resturned by Arrays.asList and shuffle that... 存储由Arrays.asList重新存储的列表并随机播放......

List myShuffledList = Arrays.asList(arr);
Collections.shuffle(myShuffledList);

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

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