使用 Enumeration<E> 的 hasMoreElements() 和 nextElement() 方法打印列表,第一次成功,添加一些元素后第二次失败

using Enumeration<E> 's hasMoreElements() and nextElement() method to print a list, succeeded 1st time, failed 2nd time after adding some element

我是 Java 的新手,正在尝试学习 Enumeration 的 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());
}

输出:

two
one
localhost
after printing eString1
before printing eString1 again

这里有两点需要注意:

  1. elements() 从属性创建枚举。一旦创建,它就与属性本身断开连接。那的意思就是后面再加一个属性就不会加到枚举中了
  2. 枚举是一个'one time'对象,类似于迭代器。这意味着您可以遍历元素一次,之后,每次调用时 hasMoreElements 都会 return false。

考虑到这两个事实,第二次打印什么也没打印是完全合理的

不要忘记在再次使用之前重置您的枚举。

eString1 = p1.elements();

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

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

较新版本的 EnumerationIterator 也是如此,除了 some Iterators 提供了 remove 方法允许您在不破坏迭代器的情况下从集合中删除 "current element"。 (但是你必须使用 Iteratorremove 方法;你不能使用任何其他机制来删除元素,否则你可能会破坏迭代器。)

基本原因是 EnumerationIterator 包含有关您正在枚举的实体的状态信息。如果您修改该实体,状态信息可能不再有效。例如,假设您正在遍历 ArrayList。最有可能的是,迭代器将包含一个整数,它是数组的 "current" 索引。如果你随后在 ArrayList 的前面插入一些东西,那个索引指向的元素将变成一个不同的元素,下次你在迭代器上调用 next 时,它会查看该索引处的元素和 return 上次 return 编辑的相同元素。在你的情况下,我猜 Enumeration 中保存的一条状态信息是一个 boolean 实例变量,它说 "Have I reached the end yet?" 一旦你到达 Properties,该变量将变为 true。如果您随后添加更多属性,"end-of-the-enumeration" 变量仍然为真,即使此时它实际上是错误的。

尝试设置 EnumeratorsIterators 以便它们在底层实体发生变化时自行调整是不切实际的。 Properties 对象(或 ArrayList 或其他对象)需要跟踪从中创建的每个 EnumeratorIterator,然后找到所有对象并进行调整每当发生改变 Properties 的事情时,他们都会这样做;否则每个 EnumeratorIterator 都需要一种方法来查询 Properties 来询问它,自从我上次检查以来发生了什么变化?其中任何一个都会非常复杂。还要考虑 Properties 是一个散列 table,这样当你添加一个新元素时,你可以将它添加到散列 table 中的任何桶中。如果 Enumerator 已经扫描过那个桶,它怎么知道在添加新元素后返回并再次扫描它?我相信 可以 写出这样的 Enumerator,但效率会非常低,混乱且复杂。