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
}
}
}
}
我需要像这样存储不明确的对象(每个对象都有自己的类):
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
}
}
}
}