zoukankan      html  css  js  c++  java
  • Guava ClassToInstanceMap

    概述

    ClassToInstanceMap提供了一种是用Class作为Key, 对应实例作为Value的途径.他定义了T getInstance(Class<T>)和T putInstance(Class<T> T)两个方法, 这两个方法消除了元素类型转换的过程并保证了元素在Map中是类型安全的.

    ClassToInstanceMap有一个独立的类型参数, 一般命名为B. 它对应着Map的元素的类型的最大上界.例如

    ClassToInstanceMap<Number> numberDefaults = MutableClassToInstanceMap.create();
    numberDefaults.putInstance(Integer.class, Integer.valueOf(0));

    实现上, ClassToInstanceMap<B>实现了Map<Class<? extends B>, B> -- 换句话说, 他是一个由B的子类和B的实例构成的Map.这让泛型在ClassToInstanceMap里有点混乱,但是只需要记住B是所有map中的类型的上界就够了 -- 通常, B就是Object

    Guava提供了很有用的ClassToInstanceMap的实现 MutableClassToInstanceMap 和 ImmutableClassToInstanceMap

    重点: 就像其他 Map<Class, Object>, ClassToInstanceMap可能会包含原生类型的元素, 原生类型和它的包装类在map中可能会映射到不同的值上.但是在getInstance取值的时候会将所有原生类型都转成它的包装类.

    MutableClassToInstanceMap

    构造方法

        /**
         * 返回一个使用new HashMap<Class<? extends B>, B>()作为代理的MutableClassToInstanceMap
         * 内部调用的是MutableClassToInstanceMap(Map<Class<? extends B>, B> delegate)这个私有构造方法
         */
        public static <B> MutableClassToInstanceMap<B> create() {
            return new MutableClassToInstanceMap<B>(
                    new HashMap<Class<? extends B>, B>());
        }
    
        /**
         * 通过已存在的new HashMap<Class<? extends B>, B>()作为代理构造MutableClassToInstanceMap
         * 内部调用的是MutableClassToInstanceMap(Map<Class<? extends B>, B> delegate)这个私有构造方法
         */
        public static <B> MutableClassToInstanceMap<B> create(
                Map<Class<? extends B>, B> backingMap) {
            return new MutableClassToInstanceMap<B>(backingMap);
        }
    
        /**
         * 私有构造方法, 通过delegate和MapConstraint<Class<?>, Object>来构造ConstrainedMap并返回
         * @param delegate
         */
        private MutableClassToInstanceMap(Map<Class<? extends B>, B> delegate) {
            super(delegate, VALUE_CAN_BE_CAST_TO_KEY);
        }
    
        /**
         * 用来保证当你没有指定MutableClassToInstanceMap<B>的B类型时
         * 在V put(K key, V value)的时候V的Class是K的子类
         */
        private static final MapConstraint<Class<?>, Object> VALUE_CAN_BE_CAST_TO_KEY
                = new MapConstraint<Class<?>, Object>() {
            @Override
            public void checkKeyValue(Class<?> key, Object value) {
                cast(key, value);
            }
        };
    
        /**
         * cast()方法实际上做的事情是对原生类型的Class做一次包装
         * 并且调用Class.cast()方法,这样如果type和value对不上,则会抛出ClassCastException
         */
        private static <B, T extends B> T cast(Class<T> type, B value) {
            return Primitives.wrap(type).cast(value);
        }

    从这几个构造方法可以看出MutableClassToInstanceMap是使用代理实现的Map, 他使用了一个MapConstraint来限制当一个MCTIMap没有指定Class上界的时候put进去的Value的Class与Key的继承合法性,cast()方法会对value做一次type的cast,这样如果put进去的Value的Class不是Key的子类就会抛出异常,这也是fast fail的一种形式

    get与put

    MutableClassToInstanceMap自己实现的getInstance与putInstance

        @Override
        public <T extends B> T putInstance(Class<T> type, T value) {
            return cast(type, put(type, value));
        }
    
        @Override
        public <T extends B> T getInstance(Class<T> type) {
            return cast(type, get(type));
        }

    这两个方法都调用了cast()方法做了一次原生类型包装与类型转换(检查),下面在看看 get() 与 put() 的实现

    其中,get()使用的是ForwardingMap的get()方法

      @Override
      public V get(Object key) {
        return delegate().get(key);
      }

    这个方法很简单,也就是直接调用了delegate的get()方法,实际上就是HashMap的get()

    put()方法使用的是ConstrainedMap的put()方法

        @Override public V put(K key, V value) {
          constraint.checkKeyValue(key, value);
          return delegate.put(key, value);
        }

    这个方法调用了MapConstraint的checkKeyValue,保证了put进去的Value的类型的正确性

    不过一般来说,使用ClassToInstanceMap应该调用getInstance和putInstance, 而不是get()和put(), 下面是一个使用代码示例

            MutableClassToInstanceMap<Number> map = MutableClassToInstanceMap.create();
            map.putInstance(Integer.class, 100);
            map.putInstance(Float.class, 10.01f);
            System.out.println(map.getInstance(Integer.class));
            System.out.println(map.getInstance(Float.class));

     

    ImmutableClassToInstanceMap

    ImmutableClassToInstanceMap顾名思义就是不可变更的ClassToInstanceMap, 我们在对这个Map构造完成后边不可再变更

    它的使用和MutableClassToInstanceMap大同小异,只不过在构造完成后在调用put()或者putInstance()会抛出UnsupportedOperationException

    使用示例

            ImmutableClassToInstanceMap<Number> map =
                    new ImmutableClassToInstanceMap.Builder<Number>()
                    .put(Integer.class, 100)
                    .put(Float.class, 10.01f)
                    .build();
            ImmutableClassToInstanceMap<Number> map2 = ImmutableClassToInstanceMap.copyOf(map);
            // throws UnsupportedOperationException
            // map.putInstance(Integer.class, 1000);
            // map.put(Integer.class, 1000);
            System.out.println(map.getInstance(Integer.class));
            System.out.println(map2.getInstance(Float.class));

    之所以使用Builder来创建ImmutableClassToInstanceMap,是因为在创建的时候是可以put()的,而创建完以后返回的是另外一个类型的Map,他的put()方法被重写为直接抛出UnsupportOperationException

    总结

    我们之所以使用ClassToInstanceMap而不是使用Map<Class, Object>,就是因为ClassToInstanceMap使用了MapConstraint, 他保证了我们放入的Class和Object的类型是对应的, 而不会出现 put(Integer.class, "string")这样的情况.

  • 相关阅读:
    c++中stl函数的使用
    java 中String类的常见方法和StringBuffer类的使用
    c++模板类和模板函数
    c++简单工厂类的设计模式
    Android自定义的button按钮
    c++基类与派生类之间的转换
    Unity和Android结合出现Unabled to convert class into dex format
    jz2240用tftp下载程序步骤
    解决jz2440不能ping同主机问题
    android中的事件传递机制
  • 原文地址:https://www.cnblogs.com/zemliu/p/3335982.html
Copyright © 2011-2022 走看看