Java 使用枚举<;E>';s hasMoreElements()和nextElement()方法打印列表,第一次成功,添加某些元素后第二次失败

Java 使用枚举<;E>';s hasMoreElements()和nextElement()方法打印列表,第一次成功,添加某些元素后第二次失败,java,enumeration,Java,Enumeration,我是Java新手,正在尝试学习枚举的hasMoreElements()和nextElement()方法。在我将一些元素添加到p1列表中,同时从p1列表中删除了其他元素之后,我尝试打印所有内容,但是,打印失败了?为什么会这样 Properties p1 = new Properties(); try (OutputStream os1 = new FileOutputStream("xanadu123.properties")) { //set the properties valu

我是Java新手,正在尝试学习枚举的hasMoreElements()和nextElement()方法。在我将一些元素添加到
p1
列表中,同时从
p1
列表中删除了其他元素之后,我尝试打印所有内容,但是,打印失败了?为什么会这样

Properties p1 = new Properties();

try (OutputStream os1  = new FileOutputStream("xanadu123.properties")) {

    //set the properties value
    p1.setProperty("database", "localhost");
    p1.setProperty("1", "one");
    p1.setProperty("2", "two");

} catch (IOException e) {
    e.printStackTrace();
}

Enumeration<Object> eString1 = p1.elements();
while (eString1.hasMoreElements()) {
    System.out.println(eString1.nextElement());
}

System.out.println("after printing eString1");

p1.setProperty("3", "three");
p1.remove("2");

System.out.println("before printing eString1 again");

while (eString1.hasMoreElements()) {
    System.out.println(eString1.nextElement());
}

这里有两件事需要注意:

  • elements()
    从属性创建枚举。创建后,它将与属性本身断开连接。这意味着之后再添加一个属性将不会添加到枚举中
  • 枚举是一个“一次性”对象,类似于迭代器。这意味着您可以在元素上循环一次,之后,
    hasMoreElements
    将在每次调用它时返回false

  • 考虑到这两个事实,第二次打印什么也不打印是完全有道理的。在再次使用它之前,不要忘记重置枚举

    eString1 = p1.elements();
    
    while (eString1.hasMoreElements()) {
        System.out.println(eString1.nextElement());
    }
    

    基本答案是,如果修改正在枚举的内容(在本例中为
    属性
    ),则不能依赖
    枚举
    工作。一旦这样做,您构建的
    枚举可能不再有效

    较新版本的
    枚举
    迭代器
    ,与此相同,只是一些
    迭代器
    提供了一个
    删除
    方法,允许您从集合中删除“当前元素”,而不破坏迭代器。(但是您必须使用
    迭代器的
    删除
    方法;您不能使用任何其他机制删除元素,否则可能会破坏迭代器。)

    基本原因是
    枚举
    迭代器
    包含有关正在枚举的实体的状态信息。如果修改该实体,状态信息可能不再有效。例如,假设您正在迭代一个
    ArrayList
    。迭代器很可能包含一个整数,该整数是数组的“当前”索引。如果随后在
    ArrayList
    的前面插入一些内容,则该索引指向的元素将成为不同的元素,下次在迭代器上调用
    next
    ,它将查看该索引处的元素,并返回上次返回的相同元素。在您的例子中,我猜
    枚举
    中保存的一条状态信息是一个
    布尔
    实例变量,它会说,“我到了末尾了吗?”一旦到达
    属性
    的末尾,该变量将变为
    。如果随后添加更多属性,“枚举结束”变量仍然为true,即使此时实际上是错误的


    试图设置
    枚举器
    迭代器
    以使它们在底层实体发生更改时进行自我调整是不实际的。
    Properties
    对象(或
    ArrayList
    或其他任何对象)需要跟踪从中创建的每个
    枚举器或
    迭代器,然后在执行任何更改
    属性的操作时查找并调整它们;或者,每个
    枚举器
    迭代器
    都需要一种方法来查询
    属性
    ,询问自上次检查以来发生了什么变化?这两个问题都非常复杂。还要考虑<代码>属性是一个哈希表,这样当你添加一个新的元素时,你可以将它添加到哈希表中的任何一个桶中。如果
    枚举器
    已经在该存储桶上进行了扫描,那么在添加新元素后,它如何知道返回并再次扫描它?我相信可以编写一个这样工作的
    枚举器
    ,但它会非常低效、混乱和复杂。

    你确定#1是正确的吗?我查看了代码,没有发现任何证据表明
    枚举
    属性
    完全断开连接。事实上,我认为
    枚举
    属性
    共享对哈希表的引用,这意味着如果添加到
    属性
    ,枚举可能会在以后看到它,也可能不会看到,这取决于新元素添加到的哈希桶。然而,我还没有测试过这个。我认为你不能指望这两种行为。@ajb-我从来没有看过代码,但正如你所说的-你不能指望它,我认为它的实现依赖于它,这可能无法实现OP所希望的。。。我想他希望在添加新元素后,
    枚举器将只打印新元素。然而,如果这就是他想要的,那是不可能的。
    
    eString1 = p1.elements();
    
    while (eString1.hasMoreElements()) {
        System.out.println(eString1.nextElement());
    }