【问题标题】:Collections.sort sorts the wrong listCollections.sort 对错误列表进行排序
【发布时间】:2018-05-10 20:17:52
【问题描述】:

我想从我的原始列表中创建一个排序列表 - 无需 Collections.sort(list) 调用更改原始列表。所以我有一个未排序的列表和一个正在排序的列表 - 来自同一个列表。

看看这段代码:

public static void main(String[] args) {
    ArrayList<Integer> list = new ArrayList();
    list.add(5);
    list.add(8);
    list.add(3);
    list.add(6);
    System.out.println("Before method list is");
    System.out.println(list);
    ArrayList<Integer> theReturnedList = sorted(list);
    System.out.println("After it is");
    System.out.println(list);
}

private static ArrayList<Integer> sorted(ArrayList<Integer> list){
    ArrayList<Integer> returnList = list;
    Collections.sort(returnList);
    return returnList;
}

list 对象被排序 - 即使我没有在其上调用 Collection.sort() 方法。如何避免?

因为我认为这会发生......

public static void main(String[] args) {
    String original = "I am an object created in main";
    String theChangedObject = change(original);
    System.out.println(original);
}

private static String change(String string){
    String changed = string;
    changed = "I was changed";
    return changed;
}

对象orginal 保持不变。

【问题讨论】:

  • 你认为ArrayList&lt;Integer&gt; returnList = list; 有什么作用?
  • 你了解引用类型的工作原理吗?
  • @lelelo:除非通过反射,Strings 是不可变的——所有会修改字符串的东西都会返回包含修改的新字符串。因此,您永远不会有一个字符串可以修改而另一个字符串不能修改的情况,因为一开始就无法修改它们。
  • @lelelo 阅读 this 以获得进一步解释。

标签: java arrays methods collections


【解决方案1】:

在这一行:

ArrayList<Integer> returnList = list;

您只是在您的 sorted 方法中创建对 相同列表(对象)的另一个引用,并且您使用此新引用对其应用的任何更改都将反映在您的原始引用中,因为它们point 指向同一个对象。您可以这样做来创建一个新列表:

private static ArrayList<Integer> sorted(ArrayList<Integer> list){
    ArrayList<Integer> returnList = new ArrayList<>(list); // the new keyword creates a new object on the memory heap
    Collections.sort(returnList);
    return returnList;
}

这一次我们用你原始列表的元素创建另一个 ArrayList 对象。这样,当您对新列表进行排序时,原始列表不会改变。

此行为不适用于 Immutable Objects,如 String 或 LocalDateTime。它们在创建后无法更改其状态,而是返回应用更改的新副本。

【讨论】:

【解决方案2】:

你可以使用 Stream api

List<Integer> list = Arrays.asList(5,8,3,6);

List<Integer> newList = list.stream().sorted().collect(Collectors.toList());

流 api 提供了几种方法来不可变地处理集合。如果您使用的是 Java 8 或更高版本,这是推荐的方式。

【讨论】:

    【解决方案3】:

    在您的sorted 方法中,您仍然在原始列表中调用Collection.sort。为避免这种情况,您可以创建一个浅拷贝并返回它,例如

    private static ArrayList<Integer> sorted(ArrayList<Integer> list){
        ArrayList<Integer> returnList = new ArrayList<>(list);
        Collections.sort(returnList);
        return returnList;
    }
    

    【讨论】:

      【解决方案4】:

      您的问题是对引用的工作方式有误解。我们来看看方法:

      private static ArrayList<Integer> sorted(ArrayList<Integer> list){
          ArrayList<Integer> returnList = list;
          Collections.sort(returnList);
          return returnList;
      }
      

      ArrayList&lt;Integer&gt; returnList = list;复制列表。它将 reference 复制到列表中。这意味着returnListlist 都将引用同一个列表。一个变化会影响另一个,因为它们实际上只是同一事物的不同名称。

      您要做的是创建一个包含相同值的全新列表,这可以通过

      ArrayList<Integer> returnList = new ArrayList<>();
      returnList.addAll(list);
      

      还有一个方便的ArrayList 构造函数可以一步完成:

      ArrayList<Integer> returnList = new ArrayList<>(list);
      

      returnList 的更改不会影响list,因为它们现在是两个完全独立的列表,恰好包含相同的值。

      【讨论】:

      • 是的。为什么我不必用字符串来做呢?
      • 字符串方法在 Java 中是不可变的。
      猜你喜欢
      • 2013-10-04
      • 2017-03-05
      • 1970-01-01
      • 2015-01-05
      • 1970-01-01
      • 1970-01-01
      • 2019-05-03
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多