• 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")这样的情况.

  • 相关阅读:
    5-python基础—获取某个目录下的文件列表(适用于任何系统)
    Automated, Self-Service Provisioning of VMs Using HyperForm (Part 1) (使用HyperForm自动配置虚拟机(第1部分)
    CloudStack Support in Apache libcloud(Apache libcloud中对CloudStack支持)
    Deploying MicroProfile-Based Java Apps to Bluemix(将基于MicroProfile的Java应用程序部署到Bluemix)
    Adding Persistent Storage to Red Hat CDK Kit 3.0 (在Red Hat CDK Kit 3.0添加永久性存储)
    Carve Your Laptop Into VMs Using Vagrant(使用Vagran把您笔记本电脑刻录成虚拟机)
    使用Python生成一张用于登陆验证的字符图片
    Jupyter notebook的安装方法
    Ubuntu16.04使用Anaconda5搭建TensorFlow使用环境 图文详细教程
    不同时区的换算
  • 原文地址:https://www.cnblogs.com/zemliu/p/3335982.html
Copyright © 2020-2023  润新知