Collections.unmodifiableMap

来源:互联网 发布:php集成包 编辑:程序博客网 时间:2024/06/05 20:28

1、场景

某些场景下需要返回不可修改Map,java容器类java.util.Collections提供了static方法unmodifiableMap来提供这个功能:

    /**     * Returns an unmodifiable view of the specified map.  This method     * allows modules to provide users with "read-only" access to internal     * maps.  Query operations on the returned map "read through"     * to the specified map, and attempts to modify the returned     * map, whether direct or via its collection views, result in an     * <tt>UnsupportedOperationException</tt>.<p>     *     * The returned map will be serializable if the specified map     * is serializable.     *     * @param  m the map for which an unmodifiable view is to be returned.     * @return an unmodifiable view of the specified map.     */    public static <K,V> Map<K,V> unmodifiableMap(Map<? extends K, ? extends V> m) {return new UnmodifiableMap<K,V>(m);    }
java.util.Collections将内部类UnmodifiableMap<K,V>权限实现为private,因此外部不能直接访问,仅能通过提供的方法unmodifiableMap获取并使用。

2、实现

    /**     * @serial include     */    private static class UnmodifiableMap<K,V> implements Map<K,V>, Serializable {// use serialVersionUID from JDK 1.2.2 for interoperabilityprivate static final long serialVersionUID = -1034234728574286014L;private final Map<? extends K, ? extends V> m;UnmodifiableMap(Map<? extends K, ? extends V> m) {            if (m==null)                throw new NullPointerException();            this.m = m;        }public int size()          {return m.size();}public boolean isEmpty()          {return m.isEmpty();}public boolean containsKey(Object key)   {return m.containsKey(key);}public boolean containsValue(Object val) {return m.containsValue(val);}public V get(Object key)          {return m.get(key);}public V put(K key, V value) {    throw new UnsupportedOperationException();        }public V remove(Object key) {    throw new UnsupportedOperationException();        }public void putAll(Map<? extends K, ? extends V> m) {    throw new UnsupportedOperationException();        }public void clear() {    throw new UnsupportedOperationException();        }private transient Set<K> keySet = null;private transient Set<Map.Entry<K,V>> entrySet = null;private transient Collection<V> values = null;public Set<K> keySet() {    if (keySet==null)keySet = unmodifiableSet(m.keySet());    return keySet;}public Set<Map.Entry<K,V>> entrySet() {    if (entrySet==null)entrySet = new UnmodifiableEntrySet<K,V>(m.entrySet());    return entrySet;}public Collection<V> values() {    if (values==null)values = unmodifiableCollection(m.values());    return values;}public boolean equals(Object o) {return o == this || m.equals(o);}public int hashCode()           {return m.hashCode();}        public String toString()        {return m.toString();}        /**         * We need this class in addition to UnmodifiableSet as         * Map.Entries themselves permit modification of the backing Map         * via their setValue operation.  This class is subtle: there are         * many possible attacks that must be thwarted.         *         * @serial include         */        static class UnmodifiableEntrySet<K,V>    extends UnmodifiableSet<Map.Entry<K,V>> {    private static final long serialVersionUID = 7854390611657943733L;            UnmodifiableEntrySet(Set<? extends Map.Entry<? extends K, ? extends V>> s) {                super((Set)s);            }            public Iterator<Map.Entry<K,V>> iterator() {                return new Iterator<Map.Entry<K,V>>() {    Iterator<? extends Map.Entry<? extends K, ? extends V>> i = c.iterator();                    public boolean hasNext() {                        return i.hasNext();                    }    public Map.Entry<K,V> next() {return new UnmodifiableEntry<K,V>(i.next());                    }                    public void remove() {                        throw new UnsupportedOperationException();                    }                };            }            public Object[] toArray() {                Object[] a = c.toArray();                for (int i=0; i<a.length; i++)                    a[i] = new UnmodifiableEntry<K,V>((Map.Entry<K,V>)a[i]);                return a;            }            public <T> T[] toArray(T[] a) {                // We don't pass a to c.toArray, to avoid window of                // vulnerability wherein an unscrupulous multithreaded client                // could get his hands on raw (unwrapped) Entries from c.Object[] arr = c.toArray(a.length==0 ? a : Arrays.copyOf(a, 0));                for (int i=0; i<arr.length; i++)                    arr[i] = new UnmodifiableEntry<K,V>((Map.Entry<K,V>)arr[i]);                if (arr.length > a.length)                    return (T[])arr;                System.arraycopy(arr, 0, a, 0, arr.length);                if (a.length > arr.length)                    a[arr.length] = null;                return a;            }            /**             * This method is overridden to protect the backing set against             * an object with a nefarious equals function that senses             * that the equality-candidate is Map.Entry and calls its             * setValue method.             */            public boolean contains(Object o) {                if (!(o instanceof Map.Entry))                    return false;                return c.contains(new UnmodifiableEntry<K,V>((Map.Entry<K,V>) o));            }            /**             * The next two methods are overridden to protect against             * an unscrupulous List whose contains(Object o) method senses             * when o is a Map.Entry, and calls o.setValue.             */            public boolean containsAll(Collection<?> coll) {                Iterator<?> e = coll.iterator();                while (e.hasNext())                    if (!contains(e.next())) // Invokes safe contains() above                        return false;                return true;            }            public boolean equals(Object o) {                if (o == this)                    return true;                if (!(o instanceof Set))                    return false;                Set s = (Set) o;                if (s.size() != c.size())                    return false;                return containsAll(s); // Invokes safe containsAll() above            }            /**             * This "wrapper class" serves two purposes: it prevents             * the client from modifying the backing Map, by short-circuiting             * the setValue method, and it protects the backing Map against             * an ill-behaved Map.Entry that attempts to modify another             * Map Entry when asked to perform an equality check.             */            private static class UnmodifiableEntry<K,V> implements Map.Entry<K,V> {                private Map.Entry<? extends K, ? extends V> e;                UnmodifiableEntry(Map.Entry<? extends K, ? extends V> e) {this.e = e;}                public K getKey()  {return e.getKey();}                public V getValue()  {return e.getValue();}                public V setValue(V value) {                    throw new UnsupportedOperationException();                }                public int hashCode()  {return e.hashCode();}                public boolean equals(Object o) {                    if (this == o)                        return true;                    if (!(o instanceof Map.Entry))                        return false;                    Map.Entry t = (Map.Entry)o;                    return eq(e.getKey(),   t.getKey()) &&                           eq(e.getValue(), t.getValue());                }                public String toString()  {return e.toString();}            }        }    }
其中,访问涉及修改的部分直接抛出异常:
public V put(K key, V value) {    throw new UnsupportedOperationException();        }public V remove(Object key) {    throw new UnsupportedOperationException();        }public void putAll(Map<? extends K, ? extends V> m) {    throw new UnsupportedOperationException();        }public void clear() {    throw new UnsupportedOperationException();        }



原创粉丝点击