Java-01-基础篇 Java集合-01-Map

news2025/7/13 19:46:41

一,Map

        Map 是一个键值对的集合,它取代了 java.util.Dictionary 字典类;这个字典类是在 JDK1.0 提供的,Map集合是在 JDK1.2 提供的。

1.1 Map 接口分析

package java.util;
/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {/*忽略代码*/}

1.2 Map 查询业务接口

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {
    /*********************** Map 查询业务   **************************/
    /** map集合大小 */
    int size();

    /** 
     * map集合是否为空;
     * @retrun true- 为空 | false - 不为空 
     */
    boolean isEmpty();

    /** 
     * 是否包含指定的key
     * @retrun true - 包含 | false - 不包含
     */
    boolean containsKey(Object key);

    /** 
     * 是否包含指定的value
     * @retrun true - 包含 | false - 不包含
     */
    boolean containsValue(Object value);

    /** 根据key获取value; 如果没有返回为null */
    V get(Object key);
    /*忽略其他代码*/
}

1.3 Map 修改(写)业务接口 

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {
    /*********************** Map 修改业务   **************************/

    /**
     * 新增键值对
     *
     * @param key 要新增的key
     * @param value 要新增的value
     * @return 返回key关联的前一个值,如果没有则返回null
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     * @throws IllegalArgumentException 非法参数异常
     */
    V put(K key, V value);

    /**
     * 删除map集合中对应的key-value 键值对
     *
     * @param key
     * @return 返回key前一个映射的值
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     */
    V remove(Object key);
    //... ... 
}

1.4 Map 批量业务接口 

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> { 

    /*********************** Map 批量业务   **************************/

    /**
     * 新增指定的元素集
     *
     * @param m 要新增的map元素集合
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     * @throws IllegalArgumentException 非法参数异常
     */
    void putAll(Map<? extends K, ? extends V> m);

    /**
     * 清空Map集合
     * @throws UnsupportedOperationException 不支持操作异常
     */
    void clear();

}

1.5 Map 视图业务

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {

    /*********************** Map的试图业务   **************************/

    /**
     * 获取 key 的所有元素,并以Set形式进行返回;
     */
    Set<K> keySet();

    /**
     * 获取 values 的所有元素,并以Collection形式进行返回
     */
    Collection<V> values();

    /**
     * 获取 key-value 的所有元素,并以Set形式进行返回;类型是Map.Entry
     */
    Set<Map.Entry<K, V>> entrySet();

    /*忽略其他代码*/ 

}

1.6 Map 的映射业务Entry

        map 是一个 key-value 的映射集合;映射业务标准定义由Entry实现;Entry 中文名称为“实体”的意思;也就是Map的元素表现就是以的形式 Entry 呈现; Entry 里面包含着 key与value ;
       那为什么不直接定义为一个 实体类 calss Entry, 然后指定定义属性key,value,再定义getting与setting呢?
       首先,接口的作用是什么?接口的作用是提供标准。没错 interface Entry 接口是为了提供映射业务实现的标准;从而不限制 Entry的具体实现方式;具体的子类可以根据自己具体的子类特性进行实现;(可参考 AbstractMap的Entry的实现)
       如果在定义Map 接口的时候,就将Entry写成一个实体类,就意味着Map的Entry实现方式就只有一种固定的,可能无法满足不同子类的需求

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {
    /*********************** Map 的映射业务 Entry **************************/
    /**
     * map 是一个 key-value 的映射集合;映射业务标准定义由Entry实现;
     * Entry 中文名称为“实体”的意思;也就是Map的元素表现就是 Entry ;
     * Entry 里面包含着 key与value ;
     * 那为什么不直接定义为一个 实体类 calss Entry, 然后指定定义属性key,value,再定义getting与setting呢?
     * 首先,接口的作用是什么?接口的作用是提供标准。没错interface Entry 是为了提供映射业务实现的标准;从而不限制 Entry的具体实现方式;具体的子类可以根据自己的特性进行实现;
     * 如果在定义Map 接口的时候,就将Entry写成一个实体类,就意味着Map的Entry实现方式就只有一种固定的,可能无法满足不同子类的需求
     * @see Map#entrySet()
     * @since 1.2
     */
    interface Entry<K, V> {
        /** 获取 key */
        K getKey();

        /** 获取 value */
        V getValue();

        /** 设置 value */
        V setValue(V value);

        /** 比较Entry是否相同 */
        boolean equals(Object o);

        /** 获取hashCode */
        int hashCode();

        /**
         * @return 根据key进行自然比较
         * @see Comparable
         * @since 1.8
         */
        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

        /**value
         * @return 根据value进行自然比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }


        /**
         * @return 根据key进行比较器进行比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }

        /**
         * @return 根据value进行比较器进行比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }

        /**
         * 复制一个Map.Entry 实体
         * @since 17
         */
        @SuppressWarnings("unchecked")
        public static <K, V> Map.Entry<K, V> copyOf(Map.Entry<? extends K, ? extends V> e) {
            Objects.requireNonNull(e);
            if (e instanceof KeyValueHolder) {
                return (Map.Entry<K, V>) e;
            } else {
                return Map.entry(e.getKey(), e.getValue());
            }
        }
    }

    /*忽略其他代码*/ 

}

1.7 Map 不可修改的业务

        JDK9 提供一些列的不可修改操作

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {
    /*********************** Map 不可修改业务 **************************/
    /**
     * 返回包含0映射实体的不可修改映射Map
     * @since 9
     */
    @SuppressWarnings("unchecked")
    static <K, V> Map<K, V> of() {
        return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1) {
        return new ImmutableCollections.Map1<>(k1, v1);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8, k9, v9);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
    }

}

        完整代码如下:

package java.util;

import java.util.function.BiConsumer;
import java.util.function.BiFunction;
import java.util.function.Function;
import java.io.Serializable;

/**
 * @param <K> 键的类型
 * @param <V> 值的类型
 *
 * @author  Josh Bloch
 * @since 1.2
 */
public interface Map<K, V> {
    /*********************** Map 查询业务   **************************/
    /** map集合大小 */
    int size();

    /** 
     * map集合是否为空;
     * @retrun true- 为空 | false - 不为空 
     */
    boolean isEmpty();

    /** 
     * 是否包含指定的key
     * @retrun true - 包含 | false - 不包含
     */
    boolean containsKey(Object key);

    /** 
     * 是否包含指定的value
     * @retrun true - 包含 | false - 不包含
     */
    boolean containsValue(Object value);

    /** 根据key获取value; 如果没有返回为null */
    V get(Object key);

    /*********************** Map 修改业务   **************************/

    /**
     * 新增键值对
     *
     * @param key 要新增的key
     * @param value 要新增的value
     * @return 返回key关联的前一个值,如果没有则返回null
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     * @throws IllegalArgumentException 非法参数异常
     */
    V put(K key, V value);

    /**
     * 删除map集合中对应的key-value 键值对
     *
     * @param key
     * @return 返回key前一个映射的值
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     */
    V remove(Object key);


    /*********************** Map 批量业务   **************************/

    /**
     * 新增指定的元素集
     *
     * @param m 要新增的map元素集合
     * @throws UnsupportedOperationException 不支持操作异常
     * @throws ClassCastException 类型转换异常
     * @throws NullPointerException 空指针异常
     * @throws IllegalArgumentException 非法参数异常
     */
    void putAll(Map<? extends K, ? extends V> m);

    /**
     * 清空Map集合
     * @throws UnsupportedOperationException 不支持操作异常
     */
    void clear();


    /*********************** Map的视图业务   **************************/

    /**
     * 获取 key 的所有元素,并以Set形式进行返回;
     */
    Set<K> keySet();

    /**
     * 获取 values 的所有元素,并以Collection形式进行返回
     */
    Collection<V> values();

    /**
     * 获取 key-value 的所有元素,并以Set形式进行返回;类型是Map.Entry
     */
    Set<Map.Entry<K, V>> entrySet();

    /*********************** Map 的映射业务 Entry **************************/
    /**
     * map 是一个 key-value 的映射集合;映射业务标准定义由Entry实现;
     * Entry 中文名称为“实体”的意思;也就是Map的元素表现就是 Entry ;
     * Entry 里面包含着 key与value ;
     * 那为什么不直接定义为一个 实体类 calss Entry, 然后指定定义属性key,value,再定义getting与setting呢?
     * 首先,接口的作用是什么?接口的作用是提供标准。没错interface Entry 是为了提供映射业务实现的标准;从而不限制 Entry的具体实现方式;具体的子类可以根据自己的特性进行实现;
     * 如果在定义Map 接口的时候,就将Entry写成一个实体类,就意味着Map的Entry实现方式就只有一种固定的,可能无法满足不同子类的需求
     * @see Map#entrySet()
     * @since 1.2
     */
    interface Entry<K, V> {
        /** 获取 key */
        K getKey();

        /** 获取 value */
        V getValue();

        /** 设置 value */
        V setValue(V value);

        /** 比较Entry是否相同 */
        boolean equals(Object o);

        /** 获取hashCode */
        int hashCode();

        /**
         * @return 根据key进行自然比较
         * @see Comparable
         * @since 1.8
         */
        public static <K extends Comparable<? super K>, V> Comparator<Map.Entry<K, V>> comparingByKey() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getKey().compareTo(c2.getKey());
        }

        /**value
         * @return 根据value进行自然比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V extends Comparable<? super V>> Comparator<Map.Entry<K, V>> comparingByValue() {
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> c1.getValue().compareTo(c2.getValue());
        }


        /**
         * @return 根据key进行比较器进行比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByKey(Comparator<? super K> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getKey(), c2.getKey());
        }

        /**
         * @return 根据value进行比较器进行比较
         * @see Comparable
         * @since 1.8
         */
        public static <K, V> Comparator<Map.Entry<K, V>> comparingByValue(Comparator<? super V> cmp) {
            Objects.requireNonNull(cmp);
            return (Comparator<Map.Entry<K, V>> & Serializable)
                (c1, c2) -> cmp.compare(c1.getValue(), c2.getValue());
        }

        /**
         * 复制一个Map.Entry 实体
         * @since 17
         */
        @SuppressWarnings("unchecked")
        public static <K, V> Map.Entry<K, V> copyOf(Map.Entry<? extends K, ? extends V> e) {
            Objects.requireNonNull(e);
            if (e instanceof KeyValueHolder) {
                return (Map.Entry<K, V>) e;
            } else {
                return Map.entry(e.getKey(), e.getValue());
            }
        }
    }

    // Comparison and hashing
    boolean equals(Object o);

    int hashCode();

    /*********************** Map 的 Defaultable 方法 **************************/

    /**
     * 返回指定key映射的值,如果key没有映射的值则返回defaultValue值
     *
     * @param key 指定的key
     * @param defaultValue 默认值
     * @since 1.8
     */
    default V getOrDefault(Object key, V defaultValue) {
        V v;
        return (((v = get(key)) != null) || containsKey(key))
            ? v
            : defaultValue;
    }

    /**
     * 对此Map中的每个映射实体类执行给定的操作
     * @since 1.8
     */
    default void forEach(BiConsumer<? super K, ? super V> action) {
        Objects.requireNonNull(action);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
            action.accept(k, v);
        }
    }

    /**
     * 将每个映射实体类的值替换为调用给定方法的结果;直到所有的表项都被处理完为止
     * @since 1.8
     */
    default void replaceAll(BiFunction<? super K, ? super V, ? extends V> function) {
        Objects.requireNonNull(function);
        for (Map.Entry<K, V> entry : entrySet()) {
            K k;
            V v;
            try {
                k = entry.getKey();
                v = entry.getValue();
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }

            // ise thrown from function is not a cme.
            v = function.apply(k, v);

            try {
                entry.setValue(v);
            } catch (IllegalStateException ise) {
                // this usually means the entry is no longer in the map.
                throw new ConcurrentModificationException(ise);
            }
        }
    }

    /**
     * 如果当前key没有映射的value;则将指定的value进行绑定;否则不处理
     * @since 1.8
     */
    default V putIfAbsent(K key, V value) {
        V v = get(key);
        if (v == null) {
            v = put(key, value);
        }

        return v;
    }

    /**
     * key所关联的value;必须和传入的value一致才能被删除
     * @since 1.8
     */
    default boolean remove(Object key, Object value) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, value) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        remove(key);
        return true;
    }

    /**
     * key所关联的value;必须和传入的oldValue一致才能被newValue所替换
     * @since 1.8
     */
    default boolean replace(K key, V oldValue, V newValue) {
        Object curValue = get(key);
        if (!Objects.equals(curValue, oldValue) ||
            (curValue == null && !containsKey(key))) {
            return false;
        }
        put(key, newValue);
        return true;
    }

    /**
     * key所关联的value;必须和传入的value一致才能被替换
     * @since 1.8
     */
    default V replace(K key, V value) {
        V curValue;
        if (((curValue = get(key)) != null) || containsKey(key)) {
            curValue = put(key, value);
        }
        return curValue;
    }

    /**
     * 如果指定的key所映射的value为空,则尝试将mappingFunction 的value与key进行关联映射
     *
     * @since 1.8
     */
    default V computeIfAbsent(K key,
            Function<? super K, ? extends V> mappingFunction) {
        Objects.requireNonNull(mappingFunction);
        V v;
        if ((v = get(key)) == null) {
            V newValue;
            if ((newValue = mappingFunction.apply(key)) != null) {
                put(key, newValue);
                return newValue;
            }
        }

        return v;
    }

    /**
     * 如果指定key的值存在且非空,则尝试将remappingFunction的value与key进行关联映射
     * @since 1.8
     */
    default V computeIfPresent(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue;
        if ((oldValue = get(key)) != null) {
            V newValue = remappingFunction.apply(key, oldValue);
            if (newValue != null) {
                put(key, newValue);
                return newValue;
            } else {
                remove(key);
                return null;
            }
        } else {
            return null;
        }
    }

    /**
     * remappingFunction 的value 如果不为空,则于key进行关联映射,
     * 如果key所关联的value != null,则删除key; 否则key于remappingFunction 的value 进行关联映射
     */
    default V compute(K key,
            BiFunction<? super K, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        V oldValue = get(key);

        V newValue = remappingFunction.apply(key, oldValue);
        if (newValue == null) {
            // delete mapping
            if (oldValue != null || containsKey(key)) {
                // something to remove
                remove(key);
                return null;
            } else {
                // nothing to do. Leave things as they were.
                return null;
            }
        } else {
            // add or replace old mapping
            put(key, newValue);
            return newValue;
        }
    }

    /**
     * @since 1.8
     */
    default V merge(K key, V value,
            BiFunction<? super V, ? super V, ? extends V> remappingFunction) {
        Objects.requireNonNull(remappingFunction);
        Objects.requireNonNull(value);
        V oldValue = get(key);
        V newValue = (oldValue == null) ? value :
                   remappingFunction.apply(oldValue, value);
        if (newValue == null) {
            remove(key);
        } else {
            put(key, newValue);
        }
        return newValue;
    }


    /*********************** Map 不可修改业务 **************************/
    /**
     * 返回包含0映射实体的不可修改映射Map
     * @since 9
     */
    @SuppressWarnings("unchecked")
    static <K, V> Map<K, V> of() {
        return (Map<K,V>) ImmutableCollections.EMPTY_MAP;
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1) {
        return new ImmutableCollections.Map1<>(k1, v1);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8, k9, v9);
    }

    /**
     * @since 9
     */
    static <K, V> Map<K, V> of(K k1, V v1, K k2, V v2, K k3, V v3, K k4, V v4, K k5, V v5,
                               K k6, V v6, K k7, V v7, K k8, V v8, K k9, V v9, K k10, V v10) {
        return new ImmutableCollections.MapN<>(k1, v1, k2, v2, k3, v3, k4, v4, k5, v5,
                                               k6, v6, k7, v7, k8, v8, k9, v9, k10, v10);
    }

    /**
     * 返回一个不可修改的映射,其中包含从给定项提取的键和值
     * @since 9
     */
    @SafeVarargs
    @SuppressWarnings("varargs")
    static <K, V> Map<K, V> ofEntries(Entry<? extends K, ? extends V>... entries) {
        if (entries.length == 0) { // implicit null check of entries array
            @SuppressWarnings("unchecked")
            var map = (Map<K,V>) ImmutableCollections.EMPTY_MAP;
            return map;
        } else if (entries.length == 1) {
            // implicit null check of the array slot
            return new ImmutableCollections.Map1<>(entries[0].getKey(),
                    entries[0].getValue());
        } else {
            Object[] kva = new Object[entries.length << 1];
            int a = 0;
            for (Entry<? extends K, ? extends V> entry : entries) {
                // implicit null checks of each array slot
                kva[a++] = entry.getKey();
                kva[a++] = entry.getValue();
            }
            return new ImmutableCollections.MapN<>(kva);
        }
    }

    /**
     * 返回一个包含给定键和值的不可修改的
     * @see Map#ofEntries Map.ofEntries()
     * @since 9
     */
    static <K, V> Entry<K, V> entry(K k, V v) {
        // KeyValueHolder checks for nulls
        return new KeyValueHolder<>(k, v);
    }

    /**
     * 复制Map
     * @since 10
     */
    @SuppressWarnings({"rawtypes","unchecked"})
    static <K, V> Map<K, V> copyOf(Map<? extends K, ? extends V> map) {
        if (map instanceof ImmutableCollections.AbstractImmutableMap) {
            return (Map<K,V>)map;
        } else {
            return (Map<K,V>)Map.ofEntries(map.entrySet().toArray(new Entry[0]));
        }
    }
}

二,AbstractMap

        java.util.AbstractMap 是 Java 集合框架中的一个抽象类,它为实现 Map 接口提供了骨架实现。AbstractMap 类的目的是简化自定义映射实现的创建过程,减少需要实现的代码量。它提供了一些默认实现,并声明了一些需要子类具体实现的方法。 

2.1 AbstractMap 构造方法

    protected AbstractMap() {}

2.2 AbstractMap 查询业务

2.2.1 size()

    public int size() {
        return entrySet().size();
    }

2.2.2 isEmpty()

    public boolean isEmpty() {
        return size() == 0;
    }

2.2.3 containsValue(value)

    /**
     * 是否包含指定的value
     * true - 包含 | false - 不包含
     */
    public boolean containsValue(Object value) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        // 如果比较包含value的内容是 null; 
        if (value==null) {
            while (i.hasNext()) {
                // 则进行遍历map,逐个获取value是否有 null; 有则返回true
                Entry<K,V> e = i.next();
                if (e.getValue()==null)
                    return true;
            }
        } else {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                // 进行遍历map,逐个获取value是否与传入的value相同; 相同则返回true
                if (value.equals(e.getValue()))
                    return true;
            }
        }
        return false;
    }

2.2.4 containsKey(key)

    /**
     * 是否包含指定的key
     * true - 包含 | false - 不包含
     */
    public boolean containsKey(Object key) {
        Iterator<Map.Entry<K,V>> i = entrySet().iterator();
        // 如果比较包含key的内容是 null; 
        if (key==null) {
            // 则进行遍历map,逐个获取key是否有 null; 有则返回true
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getKey()==null)
                    return true;
            }
        } else {
            while (i.hasNext()) {
                // 进行遍历map,逐个获取key是否与传入的key相同; 相同则返回true
                Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                    return true;
            }
        }
        return false;
    }

2.2.5 get(key)

        根据 key获取指定的value

    public V get(Object key) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (key==null) {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getKey()==null)
                    return e.getValue();
            }
        } else {
            while (i.hasNext()) {
                Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                    return e.getValue();
            }
        }
        return null;
    }

2.3 AbstractMap 修改(写)业务

2.3.1 put(key,value)

    public V put(K key, V value) {
        throw new UnsupportedOperationException();
    }

2.3.2 remove(key)

        AbstractMap 提供默认删除的业务逻辑骨架,这样做的目的减少了代码量,并提供一些默认实现方法

    /**
     * 根据 key 进行删除;并返回key对应value
     *
     */
    public V remove(Object key) {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        Entry<K,V> correctEntry = null;
        // 如果传入的key 为 null
        if (key==null) { // 则通过迭代器迭代获取 为null key
            while (correctEntry==null && i.hasNext()) {
                Entry<K,V> e = i.next();
                if (e.getKey()==null)
                    correctEntry = e;
            }
        // 如果传入的 key 不为 null
        } else { // // 则通过迭代器迭代获取与传入key相同的key
            while (correctEntry==null && i.hasNext()) {
                Entry<K,V> e = i.next();
                if (key.equals(e.getKey()))
                    correctEntry = e;
            }
        }

        V oldValue = null;
        if (correctEntry !=null) { // 不为空,意味着传入的key 值在map中有对应的entry
            oldValue = correctEntry.getValue();
            i.remove(); // 进行删除
        }
        return oldValue; // 返回value
    }

2.4 AbstractMap 批量业务

2.4.1 putAll(m)

    public void putAll(Map<? extends K, ? extends V> m) {
        for (Map.Entry<? extends K, ? extends V> e : m.entrySet())
            put(e.getKey(), e.getValue());
    }

2.4.2 clear()

    public void clear() {
        entrySet().clear();
    }

2.5 AbstractMap 视图业务

    transient Set<K>        keySet;
    transient Collection<V> values;

2.5.1 keySet()

         在Map 里面 视图的概念是什么?其实就是以集合的形式展现。这些视图允许我们查看、操作和迭代 Map 的内容;而内容又进行分类管理。分为 KeySet (key 的集合),values (value的集合),entrySet (Entry 映射实体类的集合)

        在 AbstractMap 抽象类里面都默认提供 keySet(), values(), entrySet() 视图业务逻辑骨架;像获取key 的集合;就是一个Set集合;原因很简单,key不能重复;所以当然用Set进行接收;不管里面都是调用 AbstractMap 抽象类自己业务方法;意味着具体实现由子类来决定

public Set<K> keySet() {
        Set<K> ks = keySet;
        if (ks == null) {
            ks = new AbstractSet<K>() {
                public Iterator<K> iterator() {
                    return new Iterator<K>() {
                        private Iterator<Entry<K,V>> i = entrySet().iterator();

                        public boolean hasNext() {
                            return i.hasNext();
                        }

                        public K next() {
                            return i.next().getKey();
                        }

                        public void remove() {
                            i.remove();
                        }
                    };
                }

                public int size() {
                    return AbstractMap.this.size();
                }

                public boolean isEmpty() {
                    return AbstractMap.this.isEmpty();
                }

                public void clear() {
                    AbstractMap.this.clear();
                }

                public boolean contains(Object k) {
                    return AbstractMap.this.containsKey(k);
                }
            };
            keySet = ks;
        }
        return ks;
    }

2.5.2 values()

public Collection<V> values() {
        Collection<V> vals = values;
        if (vals == null) {
            vals = new AbstractCollection<V>() {
                public Iterator<V> iterator() {
                    return new Iterator<V>() {
                        private Iterator<Entry<K,V>> i = entrySet().iterator();

                        public boolean hasNext() {
                            return i.hasNext();
                        }

                        public V next() {
                            return i.next().getValue();
                        }

                        public void remove() {
                            i.remove();
                        }
                    };
                }

                public int size() {
                    return AbstractMap.this.size();
                }

                public boolean isEmpty() {
                    return AbstractMap.this.isEmpty();
                }

                public void clear() {
                    AbstractMap.this.clear();
                }

                public boolean contains(Object v) {
                    return AbstractMap.this.containsValue(v);
                }
            };
            values = vals;
        }
        return vals;
    }

2.5.3 entrySet()

    public abstract Set<Entry<K,V>> entrySet();

2.6  Comparison & hashing

2.6.1 equals(o)

    public boolean equals(Object o) {
        if (o == this)
            return true;

        if (!(o instanceof Map<?, ?> m))
            return false;
        if (m.size() != size())
            return false;

        try {
            for (Entry<K, V> e : entrySet()) {
                K key = e.getKey();
                V value = e.getValue();
                if (value == null) {
                    if (!(m.get(key) == null && m.containsKey(key)))
                        return false;
                } else {
                    if (!value.equals(m.get(key)))
                        return false;
                }
            }
        } catch (ClassCastException unused) {
            return false;
        } catch (NullPointerException unused) {
            return false;
        }

        return true;
    }

2.6.2 hashCode()

    public int hashCode() {
        int h = 0;
        for (Entry<K, V> entry : entrySet())
            h += entry.hashCode();
        return h;
    }

2.7 AbstractMap 其他业务

2.7.1 toString()

public String toString() {
        Iterator<Entry<K,V>> i = entrySet().iterator();
        if (! i.hasNext())
            return "{}";

        StringBuilder sb = new StringBuilder();
        sb.append('{');
        for (;;) {
            Entry<K,V> e = i.next();
            K key = e.getKey();
            V value = e.getValue();
            sb.append(key   == this ? "(this Map)" : key);
            sb.append('=');
            sb.append(value == this ? "(this Map)" : value);
            if (! i.hasNext())
                return sb.append('}').toString();
            sb.append(',').append(' ');
        }
    }

2.7.2 clone()

    protected Object clone() throws CloneNotSupportedException {
        AbstractMap<?,?> result = (AbstractMap<?,?>)super.clone();
        result.keySet = null;
        result.values = null;
        return result;
    }

2.7.3 eq(o1, o2)

    private static boolean eq(Object o1, Object o2) {
        return o1 == null ? o2 == null : o1.equals(o2);
    }

2.8 AbstractMap 映射实体Entry接口实现

2.8.1 简单映射实体 

public static class SimpleEntry<K,V>
        implements Entry<K,V>, java.io.Serializable
    {
        @java.io.Serial
        private static final long serialVersionUID = -8499721149061103585L;

        @SuppressWarnings("serial") // Conditionally serializable
        private final K key;
        @SuppressWarnings("serial") // Conditionally serializable
        private V value;

        /** 通过构造器传入 key和value */
        public SimpleEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /** 通过Entry接口创建一个SimpleEntry*/
        public SimpleEntry(Entry<? extends K, ? extends V> entry) {
            this.key   = entry.getKey();
            this.value = entry.getValue();
        }

        public K getKey() { return key; }


        public V getValue() { return value; }

        public V setValue(V value) {
            V oldValue = this.value;
            this.value = value;
            return oldValue;
        }

        public boolean equals(Object o) {
            return o instanceof Map.Entry<?, ?> e
                    && eq(key, e.getKey())
                    && eq(value, e.getValue());
        }

        public int hashCode() {
            return (key   == null ? 0 :   key.hashCode()) ^
                   (value == null ? 0 : value.hashCode());
        }

        public String toString() { return key + "=" + value; }

    }

2.8.2 不可修改的映射实体

        不可修改的 Entry 实体,只支持读取数据的操作,像getting,而setting之类则不支持操作;实现的方式就是在写操作方法里面直接抛 UnsupportedOperationException 不支持操作异常;这样就达到不可修改的目的;这里不可修改指定的Entry 的实体内容;而非引用;

    public static class SimpleImmutableEntry<K,V>
        implements Entry<K,V>, java.io.Serializable
    {
        @java.io.Serial
        private static final long serialVersionUID = 7138329143949025153L;

        @SuppressWarnings("serial") // Not statically typed as Serializable
        private final K key;
        @SuppressWarnings("serial") // Not statically typed as Serializable
        private final V value;

        /**
         * 通过传入的key和value创建一个SimpleImmutableEntry
         */
        public SimpleImmutableEntry(K key, V value) {
            this.key   = key;
            this.value = value;
        }

        /** 通过 Entry 接口创建一个SimpleImmutableEntry */
        public SimpleImmutableEntry(Entry<? extends K, ? extends V> entry) {
            this.key   = entry.getKey();
            this.value = entry.getValue();
        }

        public K getKey() { return key; }

        public V getValue() { return value; }

        public V setValue(V value) {
            throw new UnsupportedOperationException();
        }

        public boolean equals(Object o) {
            return o instanceof Map.Entry<?, ?> e
                    && eq(key, e.getKey())
                    && eq(value, e.getValue());
        }

        public int hashCode() {
            return (key   == null ? 0 :   key.hashCode()) ^
                   (value == null ? 0 : value.hashCode());
        }

        public String toString() {
            return key + "=" + value;
        }

    }

三,AbstractImmutableMap

        java.util.ImmutableCollections.AbstractImmutableMap 是 Java 中一个内部抽象类,专门用于表示不可变的映射(Map)。不可变映射是指一旦创建,其内容就不能被修改的映射。这种不可变特性在多线程环境中非常有用,因为它们本质上是线程安全的。

        这个类是在 ImmutableCollections 工具类当中,从名称也可以得知这是专门用来处理不可修改集合的。包括List, Set, Map;这些接口都有对应的不可修改集合; 

        不能发现  AbstractImmutableMap 抽象类所以有关写操作调用的都是 uoe(); 

        uoe()方法就是直接抛出一个 UnsupportedOperationException 不支持操作异常;表示不支持该操作,通过这样的形式来实现集合不可修改的特性;因为只要一旦调用put, remove等等操作就是抛 UnsupportedOperationException 不支持操作异常;

3.1 Map1 & MapN

        不管怎么说 AbstractImmutableMap 终究只是对不可修改提供一个抽象类,提供不可修改的基本业务骨架;就是通过调用 uoe();抛 UnsupportedOperationException 异常实现。

        具体的子类有哪些?在Java里面提供两种一个 Map1; 一个是 MapN;

3.2 Map1 和 MapN 的区别

        Map1: 适用于仅包含一个键值对的不可变映射。它是为单元素映射进行特殊优化的实现。
        MapN: 适用于包含多个键值对的不可变映射。它是为多元素映射设计的实现。


【内部实现】

        Map1: 由于只包含一个键值对,其内部实现非常简单。它直接存储键和值,没有复杂的数据结构。

         MapN:适用于多个键值对,因此其内部实现要复杂一些,使用了更复杂的数据结构(如数组)来存储多个键值对

【性能优化

  • Map1: 由于只处理一个键值对,操作非常快速,内存占用也非常小。
  • MapN: 虽然支持多个键值对,但仍然进行了优化,以确保在处理少量键值对时具有较好的性能。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1822085.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

『大模型笔记』主成分分析(PCA)解释:简化机器学习中的复杂数据!

主成分分析(PCA)解释:简化机器学习中的复杂数据 文章目录 一. 主成分分析(PCA)解释:简化机器学习中的复杂数据!二. 参考文献一. 主成分分析(PCA)解释:简化机器学习中的复杂数据! 主成分分析(Principal Component Analysis,简称PCA)通过 将大型数据集中的维度减少…

EC20通信模块升级失败 Quectel QDLoader 9008

这里写自定义目录标题 usb驱动下载固件和升级软件下载开始升级上述过程升级失败&#xff0c;出现Quectel QDLoader 9008寻找解决方案&#xff0c;事了QPS t不行&#xff0c;最终使用这个Quectel_Customer_FW_Download_Tool软件解决下载链接&#xff1a; 所有下载驱动、固件、软…

基于梯度下降的多元线性回归原理

为了展示多元线性回归的迭代过程&#xff0c;我们可以使用梯度下降算法手动实现多元线性回归。梯度下降是一种迭代优化算法&#xff0c;用于最小化损失函数。 我们将以下步骤进行手动实现&#xff1a; 初始化回归系数。计算预测值和损失函数。计算梯度。更新回归系数。重复步…

机器学习python实践——数据“相关性“的一些补充性个人思考

在上一篇“数据白化”的文章中&#xff0c;说到了数据“相关性”的概念&#xff0c;但是在统计学中&#xff0c;不仅存在“相关性”还存在“独立性”等等&#xff0c;所以&#xff0c;本文主要对数据“相关性”进行一些补充。当然&#xff0c;如果这篇文章还能入得了各位“看官…

MPT(merkle Patricia trie )及理解solidity里的storage

what&#xff1f; MPT树是一种数据结构&#xff0c;用于在以太坊区块链中高效地存储和检索账户状态、交易历史和其他重要数据。MPT树的设计旨在结合Merkle树和Patricia树的优点&#xff0c;以提供高效的数据存储和验证 MPT树由四种类型的节点组成&#xff1a; **扩展节点&…

快速理解 Node.js 版本差异:3 分钟指南

Node.js 是一个广泛使用的 JavaScript 运行时环境&#xff0c;允许开发者在服务器端运行 JavaScript 代码。随着技术的发展&#xff0c;Node.js 不断推出新版本&#xff0c;引入新特性和改进。了解不同版本之间的差异对于开发者来说至关重要。以下是一个快速指南&#xff0c;帮…

轻量级的数据交换格式JSON (JavaScript Object Notation)介绍

什么是JSON&#xff1f; JSON (JavaScript Object Notation) 是一种轻量级的数据交换格式&#xff0c;它属于JavaScript的一个子集&#xff0c;采用完全独立于编程语言的文本格式来存储和表示数据。简洁和清晰的层次结构使得 JSON 成为理想的数据交换语言。 JSON具有易读性&…

Ubuntu Server 20.04挂载磁盘

先查看磁盘信息&#xff1a; sudo fdisk -l然后提供NTFS文件系统支持&#xff1a; sudo mkfs.ntfs /dec/sda -F这个过程非常久… 处理完如上图。&#xff08;ps. 这个 Have a nice day. 好浪漫~&#xff09; 接着挂载磁盘&#xff1a; sudo mount /dev/sda ~/device设置开机…

安装golang

官网:All releases - The Go Programming Language (google.cn) 下载对应的版本安装即可

MongoDB——写入耗时

mongodb写入10万条数据的耗时差不多是1s import time import pymongo from pymongo import MongoClient# 连接到MongoDB client MongoClient(mongodb://localhost:27017/) db client[test_db] collection db[test_collection]# 生成10万条数据 documents [{"name&quo…

免费分享:1901-2020全球气候数据集(附下载办法)

长期的全球其后数据不仅能够揭示长期的气候趋势&#xff0c;还为农业、水资源管理、公共卫生等多个领域的决策提供科学依据&#xff0c;对于推动可持续发展具有重要意义。 数据集简介 CRU TS&#xff08;Climatic Research Unit gridded Time Series&#xff09;数据集&#…

【面经总结】Java基础 - SPI

SPI 什么是 SPI&#xff1f; 提供给服务提供者去使用的一个接口 SPI 的优点 低耦合配置灵活多态性 SPI 的应用场景 JDBCSLF4J 日志

GenIcam标准(二)—— GenApi 模块 – 配置相机

系列文章目录 GenICam标准&#xff08;一&#xff09;—— 概述 GenIcam标准&#xff08;二&#xff09;—— GenApi 模块 – 配置相机 文章目录 系列文章目录1、简介2、照相机描述文件的基本结构3、 节点、接口和抽象特征参考 1、简介 GenApi 模块解决如何去配置相机的问题。主…

论文发表CN期刊《高考》是什么级别的刊物?

论文发表CN期刊《高考》是什么级别的刊物&#xff1f; 《高考》是由吉林省长春出版社主管并主办的省级教育类期刊&#xff0c;期刊以科教兴国战略为服务宗旨&#xff0c;专门反映和探索国内外教育教学和科研实践的最新成果。该期刊致力于为广大教育工作者提供一个高质量的学术…

UDP的组播发送与接收C语言测试和nc接收组播测试

组播这个东西&#xff0c;很多年前用过一次。本身的原理不复杂&#xff0c;未知的是使用的环境&#xff0c;受使用环境的影响有多大&#xff0c;还是那句废话&#xff0c;具体问题具体分析。 发送端代码multicast.c #include <stdio.h> #include <stdlib.h> #…

大泽动力TO32000ET-Z 电动30千瓦柴油发电机规格型号参数

大泽动力30KW柴油发电机概述 大泽动力30KW柴油发电机是一种具有稳定输出功率的发电设备&#xff0c;主要用于提供电力支持。其设计结合了国外先进的低噪音发电机和发动机技术&#xff0c;使得机组在运行过程中噪音低&#xff0c;结构紧凑&#xff0c;占用空间小。以下是关于30…

DC/AC电源模块:为电动车充电基础设施提供高效能源转换

BOSHIDA DC/AC电源模块&#xff1a;为电动车充电基础设施提供高效能源转换 DC/AC电源模块是一种用于电动车充电基础设施的重要组件&#xff0c;它能够实现高效能源转换。在电动车的普及和推广过程中&#xff0c;DC/AC电源模块的重要性日益凸显。本文将从DC/AC电源模块的基本原…

Python使用策略模式实现绘图功能

策略模式&#xff08;Strategy Pattern&#xff09;:允许定义一系列算法&#xff0c;将它们封装起来&#xff0c;使得它们可以互换。 实现绘制不同类型的图表&#xff08;如折线图、柱状图和饼图&#xff09;功能。 下面是一个示例&#xff0c;展示如何传入横坐标和纵坐标内容…

探索Lua语言:安装、基本语法与应用案例

Lua Lua语言是在1993年由巴西一个大学研究小组发明的&#xff0c;其设计目标是作为嵌入式程序移植到其他应用程序。它是由C语言实现的&#xff0c;虽然简单小巧但功能强大&#xff0c;所以许多应用都选用它作为脚本语言&#xff0c;尤其是在游戏领域&#xff0c;如暴雪公司的“…

W3F 宣布第二轮 Decentralized Voices 代理者,OneBlock+ 被委托 420 万 DOT 投票权

原文&#xff1a;https://medium.com/web3foundation/decentralized-voices-cohort-2-b10ddb7c71cc 编译&#xff1a;OneBlock Web3 基金会很高兴宣布 Polkadot 和 Kusama 的去中心化声音 (DV) 计划第二批启动&#xff0c;该计划通过将 180,000 KSM 和 4200 万 DOT 的投票权委…