Hutool开发利器MapProxy类使用技巧详解

作者:JAVA旭阳 时间:2021-11-10 00:01:35 

概述

Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以“甜甜的”。

目前公司项目中主要采用Hutool作为项目的工具包,相对于google的guava, hutool的工具类采用中文注释,更加符合国人使用。所谓知己知彼,我们需要了解Hutool都具有什么样的功能,才能够最大化发挥它的价值。

本文主要就hutool 5.8.8版本中MapProxy的使用。

场景引入

其实Map在get的时候是比较危险的,你可能不知道它是什么类型,需要进行强制,举个例子如下:

@Test
public void testMapProxy1() {
   Map<String, Object> userMap = MapUtil.newHashMap(16);
   userMap.put("username", "alvin");
   userMap.put("age", 20);
   // 使用map的时候, 需要进行强转,一旦类型错误,会报错
   String age = (String)userMap.get("age");
}

运行结果:

Hutool开发利器MapProxy类使用技巧详解

那有什么更好的解决方案吗?Hutool提供了一种解决方案给我们。

MapProxy使用

依赖引入

<dependency>
 <groupId>cn.hutool</groupId>
 <artifactId>hutool-all</artifactId>
 <version>5.8.8</version>
</dependency>

定义一个可访问接口

interface MapUser {
   String getUsername();
   Integer getAge();
   MapUser setAge(Integer age);
}

通过MapProxy访问

@Test
public void testMapProxy2() {
   Map<String, Object> userMap = MapUtil.newHashMap(16);
   userMap.put("username", "alvin");
   userMap.put("age", 20);
   MapProxy mapProxy = MapProxy.create(userMap);
   Integer age = mapProxy.getInt("age", 18);
   Assert.assertTrue(age == 20);
   // 通过代理的方式
   MapUser mapUser = mapProxy.toProxyBean(MapUser.class);
   // 后续访问会变的更加安全
   Assert.assertTrue(mapUser.getAge() == 20);
   mapUser.setAge(30);
   Assert.assertTrue(mapUser.getAge() == 30);
}

MapProxy源码解析

Map代理,提供各种getXXX方法,并提供默认值支持,它的类结构图如下:

Hutool开发利器MapProxy类使用技巧详解

  • 实现了OptNullBasicTypeFromObjectGetter接口, 提供了基本类型的get, 在不提供默认值的情况下, 如果值不存在或获取错误,返回null, 比如:mapProxy.getInt("age", 18)

  • 实现了InvocationHandler接口,支持jdk的 * ,生成代理对象。

public <T> T toProxyBean(Class<T> interfaceClass) {
   return (T) Proxy.newProxyInstance(ClassLoaderUtil.getClassLoader(), new Class<?>[]{interfaceClass}, this);
}
  • toProxyBean方法就是生成代理对象,最终会调用代理类的invoke方法,这里的代理类就是MapProxy本身。

public Object invoke(Object proxy, Method method, Object[] args) {
   final Class<?>[] parameterTypes = method.getParameterTypes();
   // 如果调用方法参数为空
   if (ArrayUtil.isEmpty(parameterTypes)) {
       final Class<?> returnType = method.getReturnType();
       // 方法返回值不是void
       if (void.class != returnType) {
           // 匹配Getter
           final String methodName = method.getName();
           String fieldName = null;
           if (methodName.startsWith("get")) {
               // 匹配getXXX
               fieldName = StrUtil.removePreAndLowerFirst(methodName, 3);
           } else if (BooleanUtil.isBoolean(returnType) && methodName.startsWith("is")) {
               // 匹配isXXX
               fieldName = StrUtil.removePreAndLowerFirst(methodName, 2);
           }else if ("hashCode".equals(methodName)) {
               return this.hashCode();
           } else if ("toString".equals(methodName)) {
               return this.toString();
           }
           if (StrUtil.isNotBlank(fieldName)) {
               if (false == this.containsKey(fieldName)) {
                   // 驼峰不存在转下划线尝试
                   fieldName = StrUtil.toUnderlineCase(fieldName);
               }
               return Convert.convert(method.getGenericReturnType(), this.get(fieldName));
           }
       }
       // 如果方法参数不为空
   } else if (1 == parameterTypes.length) {
       // 匹配Setter
       final String methodName = method.getName();
       if (methodName.startsWith("set")) {
           final String fieldName = StrUtil.removePreAndLowerFirst(methodName, 3);
           if (StrUtil.isNotBlank(fieldName)) {
               this.put(fieldName, args[0]);
               final Class<?> returnType = method.getReturnType();
               // 判断返回类型是不是代理类的实例
               if(returnType.isInstance(proxy)){
                   return proxy;
               }
           }
       } else if ("equals".equals(methodName)) {
           return this.equals(args[0]);
       }
   }
   throw new UnsupportedOperationException(method.toGenericString());
}

来源:https://juejin.cn/post/7150683679730171917

标签:Hutool,MapProxy,类
0
投稿

猜你喜欢

  • java 数据结构单链表的实现

    2022-07-24 09:45:33
  • Android中获取apk安装包信息的方法

    2022-11-07 01:46:30
  • 详解Spring如何解析占位符

    2023-11-27 12:44:46
  • jdbc和mybatis的流式查询使用方法

    2023-08-24 15:39:25
  • 使用Maven配置Spring的方法步骤

    2023-02-05 18:37:46
  • Java中lambda表达式的基本运用

    2023-09-09 08:02:36
  • SpringMvc+Mybatis+Pagehelper分页详解

    2021-08-13 14:15:11
  • Java Swing实现JTable检测单元格数据变更事件的方法示例

    2022-10-16 19:49:29
  • 深入理解java中的重载和覆盖

    2023-01-05 00:24:22
  • Android7.0 工具类:DiffUtil详解

    2023-02-24 01:43:46
  • MapStruct对象映射转换解决Bean属性拷贝性能问题

    2023-05-14 04:10:55
  • java的Arrays工具类实战

    2023-08-21 15:46:36
  • android shape实现阴影或模糊边效果

    2022-10-14 02:01:09
  • Android.bp语法和使用方法讲解

    2022-09-29 19:31:19
  • DevExpress SplitContainerControl用法总结

    2022-06-13 22:10:24
  • 两个例子了解java中的回调机制

    2023-07-12 21:12:46
  • 解析Java内存分配和回收策略以及MinorGC、MajorGC、FullGC

    2023-02-06 08:22:19
  • SpringBoot实现接口数据的加解密功能

    2023-06-30 00:11:01
  • Java spring的三种注入方式详解流程

    2021-07-02 12:25:47
  • Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法详解

    2023-04-09 08:51:30
  • asp之家 软件编程 m.aspxhome.com