0

LinkedHashSetの Java ドキュメントには、次のように記載されています。

要素がセットに再挿入されても、挿入順序は影響を受けないことに注意してください。(呼び出しの直前に s.contains(e) が true を返すときに s.add(e) が呼び出されると、要素 e はセット s に再挿入されます。)

最近のプロジェクトでは、リスト ビュー ウィジェットでユーザーに表示するために、クライアント サーバー通信で一連のデータ トークンを保持するために 1 つを使用することにしました。更新されたデータで要素を安価に再挿入でき、順序が変わらないため、ユーザーは驚かないという考えです。

この短いテスト プログラムが示すように、明らかにそうではありません。Oracle JRE 1.7.0_55-b13 を使用すると、他のSetと同じように動作します。

import java.util.LinkedHashSet;

import static java.util.Arrays.deepToString;

public class LhsStack 
{
    public static class T 
    {
        public T ( int id ) { this.id = id; }

        public final Integer id;
        public String value;

        @Override
        public int hashCode () { return id.hashCode (); }

        @Override
        public boolean equals ( Object obj ) 
        { 
            return obj instanceof T && id.equals ( ((T)obj).id ); 
        }

        @Override
        public String toString () { return id + " => " + value; }
    }

    public static void main ( String [] args )
    {
        LinkedHashSet < T > set = new LinkedHashSet <> ();

        T a = new T ( 1 ),
          b = new T ( 1 ),
          c = new T ( 2 ),
          d = new T ( 3 );

        a.value = "Hello, World";
        b.value = "World, Hello";
        c.value = "Foo";
        d.value = "Bar"; 

        System.out.println ( "a == b: " + a.equals ( b ) );

        if ( set.add ( a ) ) {
            System.out.println ( "Inserted: " + a.value );
        }

        System.out.println ( "set.contains ( a ): " + set.contains ( a ) );
        System.out.println ( "set.contains ( b ): " + set.contains ( b ) );

        set.add ( c ); set.add ( d );

        System.out.println ( "Elements: " + set.size () );
        System.out.println ( deepToString ( set.toArray () ) );

        if ( set.add ( b ) ) {
            System.out.println ( "Re-Inserted: " + b.value );
        }
        else
        {
            System.out.println ( "Removing and Adding: " + b.value );
            set.remove ( b );
            set.add ( b );
        }

        System.out.println ( "Elements: " + set.size () );
        System.out.println ( deepToString ( set.toArray () ) );
    }
}

出力

a == b: true
Inserted: Hello, World
set.contains ( a ): true
set.contains ( b ): true
Elements: 3
[1 => Hello, World, 2 => Foo, 3 => Bar]
Removing and Adding: World, Hello
Elements: 3
[2 => Foo, 3 => Bar, 1 => World, Hello]

したがって、私の質問は、要素bがセットに再挿入されない (つまり、値を更新するために削除してから再度追加する必要がある) ため、Java ドキュメントのコメントの意味は何ですか?

ありがとうございました!

4

1 に答える 1

2

通常、linkedHashSet.add(elementToAdd)elementToAddの最後の要素になりlinkedHashSetます。Javadoc でのコメントの重要性は、elementToAdd既に 内linkedHashSetに表示されている場合、 はそのlinkedHashSet.add(elementToAdd)場所にそのままにしておく (最後に移動しない) ことです。

あなたがやろうとしていることについては、LinkedHashMap<Integer, T>. 次に、マッピングを更新する機能を使用して、インスタンスを反復順にvalues()取得するために反復できます。(必要に応じて、 を提供する代わりに、舞台裏でキーマッピングを処理する を提供する、ある種のコンテナ オブジェクトをTラップすることができます。実際、拡張して をベースにした実装を作成するのは非常に簡単ですの。)LinkedHashMap<Integer, T>put(Integer, T)add(T)AbstractSet<T>LinkedHashMap<Integer, T>Set<T>


更新された質問の編集:ああ、わかりました、申し訳ありませんが、あなたの混乱がよくわかりました。上記は、最初の文の目的の説明です (「要素がセットに再挿入された場合、挿入順序は影響を受けないことに注意してください」)。あなたが 2 番目の文を誤解していることに気付きませんでした (「呼び出しの直前に呼び出されたときに要素がセットに再挿入されます。」)ess.add(e)s.contains(e)true

それでは、説明させてください。2 番目の文は、「再挿入」という用語の定義にすぎません。動作を説明しているわけではありません。この文は、既に含まれている要素でLinkedHashSetそのメソッドを呼び出すと、「再挿入」と呼ばれる何かを行うと言っているのではありません。addむしろ、すでに含まれている要素でそのaddメソッドを呼び出す場合、この呼び出しは「再挿入」と呼ばれるという文です。再挿入の (非) 効果は、最初の文で説明したとおりです。つまり、要素を最後まで移動しないということです。

LinkedHashSet.addSet.addは、「指定された要素がまだ存在しない場合は、このセットに追加します (オプションの操作)。[...] このセットに既に要素が含まれている場合、呼び出しはセットを変更せずにそのままにして、 を返します。」の要件に従いますfalse。 "

実装すると主張するインターフェースの要件に従わない JDK クラスのケースがいくつかありますが、その場合は、太字の警告として呼び出され、括弧内に隠れて二度と言及されることはありません。この例については、の Javadoc をIdentityHashMap参照してください。

于 2014-05-10T02:19:53.947 に答える