Java HashSet 中的动态对象存储

Java dynamic object storage in HashSet

我需要像这样存储不明确的对象(每个对象都有自己的类):

ObjectA 
ObjectB
ObjectC

创建的 HashSet 如下所示:

public static HashSet<Object> objects = new HashSet<Object>();

然后我将对象一次一个地放置:

object.add(new ObjectA());

但是问题来了,如果以后我需要通过迭代来像这样检索某些对象:

for(Object obj : objects){
    if(obj instanceof ObjectA){
        // print that the object is A
    }
}

什么都没有发生,即使我知道那里唯一的对象是 ObjectA,我也会得到这个异常:

Caused by: java.lang.ClassCastException: java.util.HashSet$Node cannot be cast to ***.*****.******.objects.ObjectA

这是什么原因造成的?为什么对象突然不是它们自己的实例了?

此问题与泛型无关。这个问题与 Java 做 for (Object obj : objects) { ... }.

时不知道你想要什么样的 Object 有关

说明

我相信你打错了错误信息;我觉得应该是这个(重点是我加的):

Caused by: java.lang.ClassCastException: java.util.HashMap$Node cannot be cast to ***.*****.******.objects.ObjectA

错误的原因是 Java HashSet 由具有 null 的 Java HashMap 支持。在内部 HashMap 使用 HashMap$Node class 来存储它的元素:

// from the Java source code for HashMap
/**
 * Basic hash bin node, used for most entries.  (See below for
 * TreeNode subclass, and in LinkedHashMap for its Entry subclass.)
 */
// Inner class of HashMap - inner classes are always named like OuterClass$InnerClass in bytecode
static class Node<K,V> implements Map.Entry<K,V> { ... }

请记住,因为 Java 中的所有 class 最终都派生自 Object,所以当您像这样迭代 HashSet 时...

for (Object obj : objects){
    if(obj instanceof ObjectA){
        // print that the object is A
    }
}

... Object obj 可以是字面上的 任何东西 。 Java 显然 找到了它可以找到的 Object 的第一个匹配项,并决定内部 HashMap$Node class 存储元素将是 Object 的合适匹配(因为它是)。然后它继续迭代并为您提供 HashMap$Node 而不是您想要的实际值。 可能是你 ClassCastException 的原因 - 你得到了 HashMap$Node 而不是你想要的 Objects

解决方案

由于所有对象都派生自 Object,所以告诉 Java 您想要实际值的唯一方法是使用老式的Iterator<E> 增强-for 之前的方法(这将代替您当前的 for 循环):

Iterator<Object> iter = objects.iterator();
Object obj;
while (iter.hasNext()) {
    obj = iter.next();
    if (obj instanceof ObjectA) {
        // ... do stuff ...
    }
}

这应该可以像您想要的那样工作,因为它保证只给您您的值,因为它在 HashSet:

中是这样实现的
// from the Java source code for HashSet
public Iterator<E> iterator() {
    return map.keySet().iterator(); // only get the keys from the underlying HashMap, i.e. the values.
}

我们永远不会知道 OP 写了什么,但在执行与问题中描述的内容类似的操作时,您可能最终会收到报告的错误消息。 (OP 已确认错误消息指的是 HashMap$Node,而不是 HashSet$Node)。都是假设。 如果你喜欢这个,请为 dudeprgm 的回答点赞,而不是我的

public class Main {

    static class ObjectA {}

    static class ObjectB {}

    static class ObjectC {}

    public static void main(String[] args) {
        Map<Object, Integer> map = new HashMap<>();
        map.put(new ObjectA(), 1);
        map.put(new ObjectB(), 2);
        map.put(new ObjectC(), 3);
        // objects will contain ObjectA, ObjectB and ObjectC instances. 
        Set<Object> objects = new HashSet<Object>();
        objects.add(new ObjectA());
        objects.add(new ObjectB());
        objects.addAll(map.entrySet()); // Here we mean to do map.keySet().
        for (Object obj : objects) {
            if (obj instanceof ObjectB) {
                ObjectB objB = (ObjectB) obj;
                // Do something with objB
            } else if (obj instanceof ObjectC) {
                ObjectC objC = (ObjectC) obj;
                // Do something with objC
            } else {
                ObjectA objA = (ObjectA) obj;
                // Do something with objA
            }
        }
    }
}