2006-11-09
关于Map.entrySet()的疑惑
前几天项目用到Map,接着调用Map.entrySet(),结果产生了一些意外的后果.
就是,持久化数据数据的时候出现setter of com.hiber.Hibernate.Test.id 异常.
此异常是提醒,pojo里面未有属性的getter.
因为我在其他方法里面保存过,未曾出现异常,觉得甚是奇怪.后来发现,原来是Map.entrySet()搞的鬼,根据java api.
返回此映射中包含的映射关系的 set 视图。返回的 set 中的每个元素都是一个 Map.Entry。该 set 受映射支持,所以对映射的改变可在此 set 中反映出来,反之亦然。如果修改映射的同时正在对该 set 进行迭代(除了通过迭代器自己的 remove 操作,或者通过在迭代器返回的映射项上执行 setValue 操作外),则迭代结果是不明确的。set 支持通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作实现元素移除,即从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
为此,我写了一个测试代码.
就是,持久化数据数据的时候出现setter of com.hiber.Hibernate.Test.id 异常.
此异常是提醒,pojo里面未有属性的getter.
因为我在其他方法里面保存过,未曾出现异常,觉得甚是奇怪.后来发现,原来是Map.entrySet()搞的鬼,根据java api.
返回此映射中包含的映射关系的 set 视图。返回的 set 中的每个元素都是一个 Map.Entry。该 set 受映射支持,所以对映射的改变可在此 set 中反映出来,反之亦然。如果修改映射的同时正在对该 set 进行迭代(除了通过迭代器自己的 remove 操作,或者通过在迭代器返回的映射项上执行 setValue 操作外),则迭代结果是不明确的。set 支持通过 Iterator.remove、Set.remove、removeAll、retainAll 和 clear 操作实现元素移除,即从映射中移除相应的映射关系。它不支持 add 或 addAll 操作。
为此,我写了一个测试代码.
public class TestMap {
/**
* @param args
*/
public static void main(String[] args) {
Map test = new HashMap();
//测试,put进TestObject
for(int i=0; i<5; i++){
TestObject to = new TestObject();
test.put(new Integer(i), to);
}
//输出,这里进行类型强制转换,出现java.lang.ClassCastException.
for(Iterator it = test.entrySet().iterator(); it.hasNext();){
TestObjectt = (TestObject)it.next();
t.toString();
//System.out.println(t.);
}
//输出,这里直接转换成Object,并且输出的是自己定义的toString()
//且可以正常输出,为此,我不理解.为什么转换的时候保存.
//估计是里面做了些什么手脚.
for(Iterator it = test.entrySet().iterator(); it.hasNext();){
TestObjectt = (TestObject)it.next();
t.toString();
//System.out.println(t.);
}
}
}
class TestObject{
public String toString(){
System.out.println("TestObject");
return null;
}
}


评论
追究根源才是真理。
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!
但是.我如果直接转换成Object,输出的却是TestObject呢?
去看HashMap.Entry的实现啊,必然是调用了Value的toString方法咯...
上面人家已经说了呀,
你放进去的是TestObject 为什么转成Object后就该是Object 的 toString() 呀,输出是TestObject的 不是很正常?你看了map的源代码就说知道了,可这里面的关系和这个错误关系不大吧,我感觉你的理解就好象把一个对象转成接口来调用的时候方法都变空了。
愿听您详解
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!
但是.我如果直接转换成Object,输出的却是TestObject呢?
去看HashMap.Entry的实现啊,必然是调用了Value的toString方法咯...
谢谢高手的提示: 我去看了下源代码,已经搞明白了
按照提示:查看代码的流程是
1.
//获取EntrySet; public Set entrySet() { Set es = entrySet; return (es != null ? es : (entrySet = new EntrySet())); //HashMap内部实现了个EntrySet }//下面看看EntrySet的实现
private class EntrySet extends AbstractSet { //重点看看这段代码 public Iterator iterator() { return newEntryIterator(); } public boolean contains(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Entry candidate = getEntry(e.getKey()); return candidate != null && candidate.equals(e); } public boolean remove(Object o) { return removeMapping(o) != null; } public int size() { return size; } public void clear() { HashMap.this.clear(); } }得到Iterator实例:EntryIterator.
private class EntryIterator extends HashIterator { public Object next() { return nextEntry(); } } Entry nextEntry() { if (modCount != expectedModCount) throw new ConcurrentModificationException(); Entry e = next; if (e == null) throw new NoSuchElementException(); Entry n = e.next; Entry[] t = table; int i = index; while (n == null && i > 0) n = t[--i]; index = i; next = n; return current = e; } static class Entry implements Map.Entry { final Object key; Object value; final int hash; Entry next; /** * Create new entry. */ Entry(int h, Object k, Object v, Entry n) { value = v; next = n; key = k; hash = h; } public Object getKey() { return unmaskNull(key); } public Object getValue() { return value; } public Object setValue(Object newValue) { Object oldValue = value; value = newValue; return oldValue; } public boolean equals(Object o) { if (!(o instanceof Map.Entry)) return false; Map.Entry e = (Map.Entry)o; Object k1 = getKey(); Object k2 = e.getKey(); if (k1 == k2 || (k1 != null && k1.equals(k2))) { Object v1 = getValue(); Object v2 = e.getValue(); if (v1 == v2 || (v1 != null && v1.equals(v2))) return true; } return false; } public int hashCode() { return (key==NULL_KEY ? 0 : key.hashCode()) ^ (value==null ? 0 : value.hashCode()); } //最后系统调用的是这里的方法. public String toString() { return getKey() + "=" + getValue(); }哈哈.我明白了.
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!
上面没看清楚,我去查查看。
for(Iterator it = test.entrySet().iterator(); it.hasNext();){
TestObjectt = (TestObject)it.next();
t.toString();
//System.out.println(t.);
}
//输出,这里直接转换成Object,并且输出的是自己定义的toString()
//且可以正常输出,为此,我不理解.为什么转换的时候保存.
//估计是里面做了些什么手脚.
for(Iterator it = test.entrySet().iterator(); it.hasNext();){
TestObjectt = (TestObject)it.next();
t.toString();
//System.out.println(t.);
}
比较好吧
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!
但是.我如果直接转换成Object,输出的却是TestObject呢?
去看HashMap.Entry的实现啊,必然是调用了Value的toString方法咯...
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!
但是.我如果直接转换成Object,输出的却是TestObject呢?
Entry对象里是map结构的一种内部实现!
包含getKey,getValue等操作!结构类似List!
map在rehashing时会重新计算entryset!