1

次のコードがあります。

  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は値渡しですが、参照渡しだったようです。誰かが理由を理解するのを手伝ってくれますか? また、セットを一時セットにコピーし、セットを変更して最初のセットを変更しないようにするにはどうすればよいですか?

ここで非常に単純なものが欠けているように感じます。

4

3 に答える 3

6

ここには多くの問題と誤解があるので、ここにリストを示します。

a) aの要素を変更しても、引き続き機能することを期待することはできません。SetJavadocSetはより具体的です。

注: ミュータブル オブジェクトをセット要素として使用する場合は、細心の注意を払う必要があります。オブジェクトがセット内の要素であるときに、オブジェクトの値が equals 比較に影響を与える方法で変更された場合、セットの動作は指定されません。この禁止事項の特殊なケースは、集合がそれ自体を要素として含むことが許されないということです。

「不特定の動作」は、「顔の中で爆発する」または「アルバカーキで雨が降っている火曜日にのみ機能するため、半分の時間は機能し、残りの半分は爆発する可能性がある」と解釈されると常に想定してください。

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<Foo>(setToCopy)

于 2012-12-09T23:34:16.473 に答える
0

まず、使用することをお勧めしますHashSet。第二に、これらの構造は不変です。セット内の要素を変更するには、特定のメソッドを呼び出す必要があります。

于 2012-12-09T23:31:03.003 に答える
0

compareその方法はバグがあると思います。その実装を投稿できますか?

ループは変更されforませんset2。したがって、いくつかの要素があるset2間は空のままにする必要があります。set1したがって、compareメソッドは常にを返すことを期待していますfalseset2しかし、あなたが空のままになりたいとは思えませんが、それは別の問題です。

更新

メソッドはcompareスローしますjava.util.NoSuchElementExceptionhttp://ideone.com/nv1wmNを参照)。これらのバグにつながるいくつかの誤解があります。最初のステップは、が呼び出されたset2ときにそれが空であることを認識することです。compare

于 2012-12-09T23:31:51.180 に答える