0

LinkedHashSet的 java 文档说明了这一点:

请注意,如果将元素重新插入集合中,则插入顺序不受影响。(如果 s.add(e) 被调用,而 s.contains(e) 将在调用之前立即返回 true,则元素 e 被重新插入到集合 s 中。)

对于最近的一个项目,我决定使用一个在客户端-服务器通信中保存一组数据令牌,以便在某些列表视图小部件中显示给用户。我的想法是我可以用更新的数据廉价地重新插入元素,并且用户不会感到惊讶,因为顺序不会改变。

显然情况并非如此,使用 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)makeelementToAdd是 的最后一个元素linkedHashSet。Javadoc 中注释的意义在于,如果elementToAdd已经出现在 内部linkedHashSet,则将linkedHashSet.add(elementToAdd)其留在原处(并且不会将其移至末尾)。

对于您要尝试做的事情,最好使用LinkedHashMap<Integer, T>. 然后,您可以对其values()进行迭代以按迭代顺序获取您的T实例,并具有更新映射的能力。(如果需要,您可以包装LinkedHashMap<Integer, T>某种容器对象,而不是提供put(Integer, T),而是提供处理幕后键映射的 an 。事实上,扩展以创建基于 - 的实现add(T)应该非常简单的。)AbstractSet<T>LinkedHashMap<Integer, T>Set<T>


编辑更新的问题:啊,好的,对不起,我现在更好地理解了你的困惑。以上是对第一句目的的解释(“注意,如果一个元素被重新插入到集合中,插入顺序不受影响”);我没有意识到您误解了第二句话(“如果在调用之前立即返回,则将元素重新插入集合中。”)ess.add(e)s.contains(e)true

所以,让我解释一下。第二句仅仅是“重新插入”一词的定义;它没有描述任何行为。这句话并不是说如果你用它已经包含的元素LinkedHashSet调用它的方法,它就会做任何称为“重新插入”的事情。add相反,如果你add用它已经包含的元素调用它的方法,那么这个调用称为“重新插入”。重新插入的(非)效果是第一句话中解释的,即它不会将元素移动到末尾。

LinkedHashSet.add仍然遵守 的要求Set.add,它指定“如果指定的元素尚不存在,则将其添加到此集合中(可选操作)。[...] 如果此集合已包含该元素,则调用保持集合不变并返回false。 "

在某些情况下,JDK 类不遵守他们声称要实现的接口的要求,但是当这种情况发生时,它会以粗体警告的形式出现,而不仅仅是隐藏在括号内并且不再提及。有关此示例,请参阅的 Javadoc 。IdentityHashMap

于 2014-05-10T02:19:53.947 回答