【问题标题】:LinkedHashSet modifying setsLinkedHashSet 修改集
【发布时间】:2012-12-09 23:28:04
【问题描述】:

我有以下代码:

  private static class Node {
    public LinkedHashSet<String> s = new LinkedHashSet<String>();
    public Node(String s) {
        this.s.add(s);
    }
}

public static void main(String[] args) {
    LinkedHashSet<Node> set1 = new LinkedHashSet<Node>();
    set1.add(new Node("foo"));

    LinkedHashSet<Node> set2 = new LinkedHashSet<Node>(set1);

    LinkedHashSet<String> modifyingSet = new LinkedHashSet<String>();
    modifyingSet.add("modifying foo");

    for(Node n : set2) {
        n.s = new LinkedHashSet<String>(modifyingSet);
        break;
    }

    if (compare(set1, set2)) {
        System.out.println("Equal");
    } else {
        System.out.println("Not Equal");
    }

    return;
 }
private static boolean compare(LinkedHashSet<Node> h1, LinkedHashSet<Node> h2) {
      Iterator<Node> h1i = h1.iterator();
      Iterator<Node> h2i = h2.iterator();
      while (h1i.hasNext()) {
            Node n1 = h1i.next();
            Node n2 = h2i.next();
            if (n1.s.size() != n2.s.size()) {
                return false;
            } else {
                Iterator<String> it1 = n1.s.iterator();
                Iterator<String> it2 = n2.s.iterator();
                while (it1.hasNext()) {
                    String t1 = it1.next();
                    String t2 = it2.next();
                    if(!t1.equals(t2)) {
                        return false;
                    }   
                }           
            }
      }
      return true;
}

当我修改 set2 时,set1 也被字符串“test”和“bogus”修改。所以当我比较两个集合时,它们总是相等的(compare() 比较每个集合中的字符串是否相等)

我的问题是:

据我了解,Java是按值传递的,但好像是按引用传递的。谁能帮我弄清楚为什么?我怎样才能将集合复制到临时集合,然后修改集合但不修改第一个集合?

我觉得我在这里遗漏了一些非常简单的东西。

【问题讨论】:

    标签: java linkedhashset


    【解决方案1】:

    这里有很多问题和误解,所以这里列出来。

    a) 您不能修改 Set 的元素并期望它仍然有效。 Javadoc for Set 更具体:

    注意:如果将可变对象用作集合元素,则必须非常小心。如果对象的值以影响等于比较的方式更改,而对象是集合中的一个元素,则不指定集合的​​行为。这种禁止的一个特殊情况是不允许集合包含自己作为元素。

    总是假设“未指明的行为”翻译为“它会在你的脸上爆炸”或“它只会在周二阿尔伯克基下雨的时候起作用,所以它可能有一半时间起作用,另一半可能会爆炸。”

    b) 如果您不希望通过 == 比较它们,您必须覆盖 hashCode()equals(Object) 以使用 HashSetLinkedHashSet 中的对象,看起来您可能不应该在这个应用程序中。

    c) Java 按值传递引用,这不同于按值传递按引用传递。特别是,修改一个对象会影响对同一对象的所有引用,但将引用更改为引用不同的对象不会对其他引用产生影响。

    Set<Foo> set1 = new LinkedHashSet<Foo>();
    Set<Foo> set2 = set1;
    Set<Foo> set3 = set1;
    set1.add(new Foo());
    // set1, set2, and set3 each refer to the same Set, which now contains one Foo
    set3 = new LinkedHashSet<Foo>();
    // set1 and set2 still refer to the Set with one Foo;
    // set3 now refers to a new empty Set
    

    d) 要复制LinkedHashSet,只需执行new LinkedHashSet&lt;Foo&gt;(setToCopy)

    【讨论】:

      【解决方案2】:

      首先,我推荐你使用HashSet。其次,这些结构是不可变的。您必须调用特定的方法来修改集合中的元素。

      【讨论】:

        【解决方案3】:

        我认为compare 方法有问题。你能发布它的实现吗?

        for 循环不会修改 set2。所以,set2 应该保持为空,而set1 有一些元素。所以,我希望compare 方法总是返回false。但是,我怀疑您是否希望 set2 保持空白,但是,这是另一个问题。

        更新

        compare 方法抛出 java.util.NoSuchElementException(参见 http://ideone.com/nv1wmN)。有几个误解会导致这些错误。第一步是在调用compare 时意识到set2 是空的。

        【讨论】:

        • 我将代码修改为当 set2 初始化时,它会复制 set1。我同意 compare() 写得不好,但是当我处于调试模式时,我可以看到 set1 和 set2 有“修改 foo”字符串。
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-05-14
        • 1970-01-01
        • 2010-11-12
        • 2017-03-26
        • 2016-08-01
        相关资源
        最近更新 更多