java map遍历的原理

这几天做东西,有一个在把map类型的数据转为json数据,一直复用下边的函数,不是很懂就把源代码翻出来看了看,看完源码之后豁然开朗啊

	public static final String mapJSON(Map<String,String> jsonMap){
		String result = "";
		if( jsonMap == null || jsonMap.size() == 0){
			result += "{}";
			return result;
		}
		result += "{root:[";
		for(Map.Entry<String, String> entry:jsonMap.entrySet()){
			String row = "{name:'"+entry.getKey()+"',value:'"+entry.getValue()+"'}";
			result += row+",";
		}
		result = result.substring(0, result.length()-1);
		result += "]}";
		return result;
	}

这个函数可以通过类名直接访问,它将传参进来的map类型的数据转为json串返回。在遍历map时用到了Map.Entry 和 Map.entrySet(),这个entry是interface Map<K,V>下的一个接口 interface Entry<K,V>,在继承map的hashmap中实现了这个entry

   static class Entry<K,V> implements Map.Entry<K,V> {
        final K key;
        V value;
        Entry<K,V> next;
        int hash;

        /**
         * Creates new entry.
         */
        Entry(int h, K k, V v, Entry<K,V> n) {
            value = v;
            next = n;
            key = k;
            hash = h;
        }

        public final K getKey() {
            return key;
        }

        public final V getValue() {
            return value;
        }

        public final V setValue(V newValue) {
            V oldValue = value;
            value = newValue;
            return oldValue;
        }

        public final 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 final int hashCode() {
            return Objects.hashCode(getKey()) ^ Objects.hashCode(getValue());
        }

        public final String toString() {
            return getKey() + "=" + getValue();
        }

        /**
         * This method is invoked whenever the value in an entry is
         * overwritten by an invocation of put(k,v) for a key k that's already
         * in the HashMap.
         */
        void recordAccess(HashMap<K,V> m) {
        }

        /**
         * This method is invoked whenever the entry is
         * removed from the table.
         */
        void recordRemoval(HashMap<K,V> m) {
        }
    }

    /**
     * Adds a new entry with the specified key, value and hash code to
     * the specified bucket.  It is the responsibility of this
     * method to resize the table if appropriate.
     *
     * Subclass overrides this to alter the behavior of put method.
     */
    void addEntry(int hash, K key, V value, int bucketIndex) {
        if ((size >= threshold) && (null != table[bucketIndex])) {
            resize(2 * table.length);
            hash = (null != key) ? hash(key) : 0;
            bucketIndex = indexFor(hash, table.length);
        }

        createEntry(hash, key, value, bucketIndex);
    }

entry有四个属性分别是key、value、next和hash,key和value对应的是键值对,next是hashmap中要存储的下一个值,hash代表解决冲突的hash值,这样就可以通过entry.getKey()和entry.getValue()获取相应的键值。

而map.entryset()在hashmap中的实现是

   private transient Set<Map.Entry<K,V>> entrySet = null;

   public Set<Map.Entry<K,V>> entrySet() {
        return entrySet0();
    }

    private Set<Map.Entry<K,V>> entrySet0() {
        Set<Map.Entry<K,V>> es = entrySet;
        return es != null ? es : (entrySet = new EntrySet());
    }

    private final class EntrySet extends AbstractSet<Map.Entry<K,V>> {
        public Iterator<Map.Entry<K,V>> iterator() {
            return newEntryIterator();
        }
        public boolean contains(Object o) {
            if (!(o instanceof Map.Entry))
                return false;
            Map.Entry<K,V> e = (Map.Entry<K,V>) o;
            Entry<K,V> 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();
        }
    }

当调用entryset()方法时,返回的是Map.Entry<K,V>的集合,可以实现遍历。EntrySet 继承了 AbstractSet<Map.Entry<K,V>>,这就暗示了map的另一种遍历方式,即是通过迭代器Iterator来实现:

  Iterator iterator=map.entrySet().iterator();
        while(iterator.hasNext()){     
           Map.Entry<String, String> entry= (Entry<String, String>) iterator.next();
           System.out.println("key:"+entry.getKey()+" value"+entry.getValue()); 
    } 

这种方式同样可以实现遍历。相比较来说前一种:for—each只能在java5或更高的版本中使用,如果你遍历的是一个空的map对象,for-each循环将抛出NullPointerException,因此在遍历前你总是应该检查空引用。后一种:在老版本java中这是惟一遍历map的方式。另一个好处是,你可以在遍历时调用iterator.remove()来删除entries,根据javadoc的说明,如果在for-each遍历中尝试使用此方法,结果是不可预测的。

    原文作者:txxs
    原文地址: https://blog.csdn.net/maoyeqiu/article/details/45251213
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞