来源:自学PHP网 时间:2020-09-27 14:17 作者:小飞侠 阅读:次
[导读] Java8中如何通过方法引用获取属性名详解...
今天带来Java8中如何通过方法引用获取属性名详解教程详解
前言 在我们开发过程中常常有一个需求,就是要知道实体类中Getter方法对应的属性名称(Field Name),例如实体类属性到数据库字段的映射,我们常常是硬编码指定 属性名,这种硬编码有两个缺点。 1、编码效率低:因为要硬编码写属性名,很可能写错,需要非常小心,时间浪费在了不必要的检查上。 2、容易让开发人员踩坑:例如有一天发现实体类中Field Name定义的不够明确,希望换一个Field Name,那么代码所有硬编码的Field Name都要跟着变更,对于未并更的地方,是无法在编译期发现的。只要有未变更的地方都可能导致bug的出现。 而使用了方法引用后,如果Field Name变更及其对应的Getter/Setter方法变更,编译器便可以实时的帮助我们检查变更的代码,在编译器给出错误信息。 那么如何通过方法引用获取Getter方法对应的Field Name呢? Java8中给我们提供了实现方式,首先要做的就是定义一个可序列化的函数式接口(实现Serializable),实现如下: /** * Created by bruce on 2020/4/10 14:16 */ @FunctionalInterface public interface SerializableFunction<T, R> extends Function<T, R>, Serializable { } 而在使用时,我们需要传递Getter方法引用 //方法引用 SerializableFunction<People, String> getName1 = People::getName; Field field = ReflectionUtil.getField(getName1); 下面看具体怎么解析这个SerializableFunction,完整实现如下ReflectionUtil public class ReflectionUtil { private static Map<SerializableFunction<?, ?>, Field> cache = new ConcurrentHashMap<>(); public static <T, R> String getFieldName(SerializableFunction<T, R> function) { Field field = ReflectionUtil.getField(function); return field.getName(); } public static Field getField(SerializableFunction<?, ?> function) { return cache.computeIfAbsent(function, ReflectionUtil::findField); } public static Field findField(SerializableFunction<?, ?> function) { Field field = null; String fieldName = null; try { // 第1步 获取SerializedLambda Method method = function.getClass().getDeclaredMethod("writeReplace"); method.setAccessible(Boolean.TRUE); SerializedLambda serializedLambda = (SerializedLambda) method.invoke(function); // 第2步 implMethodName 即为Field对应的Getter方法名 String implMethodName = serializedLambda.getImplMethodName(); if (implMethodName.startsWith("get") && implMethodName.length() > 3) { fieldName = Introspector.decapitalize(implMethodName.substring(3)); } else if (implMethodName.startsWith("is") && implMethodName.length() > 2) { fieldName = Introspector.decapitalize(implMethodName.substring(2)); } else if (implMethodName.startsWith("lambda$")) { throw new IllegalArgumentException("SerializableFunction不能传递lambda表达式,只能使用方法引用"); } else { throw new IllegalArgumentException(implMethodName + "不是Getter方法引用"); } // 第3步 获取的Class是字符串,并且包名是“/”分割,需要替换成“.”,才能获取到对应的Class对象 String declaredClass = serializedLambda.getImplClass().replace("/", "."); Class<?> aClass = Class.forName(declaredClass, false, ClassUtils.getDefaultClassLoader()); // 第4步 Spring 中的反射工具类获取Class中定义的Field field = ReflectionUtils.findField(aClass, fieldName); } catch (Exception e) { e.printStackTrace(); } // 第5步 如果没有找到对应的字段应该抛出异常 if (field != null) { return field; } throw new NoSuchFieldError(fieldName); } } 该类中主要有如下三个方法
实现原理 1、首先我们看最后一个方法 2、 3、拿到这些信息后,便可以通过反射获取对应的Field。 4、而在方法 除此之外似乎还有一些值得思考的问题 writeReplace()方法是哪来的呢? 首先简单了解一下
概要意思就是说,如果想在序列化时改变序列化的对象,可以通过在实体类中定义任意访问权限的Object writeReplace()来改变默认序列化的对象。 那么我们的定义的SerializableFunction中并没有定义writeReplace()方法,这个方法是哪来的呢? Spring注解开发@Bean和@ComponentScan使用案例 最新评论添加评论更多文章推荐
自学PHP网专注网站建设学习,PHP程序学习,平面设计学习,以及操作系统学习 京ICP备14009008号-1@版权所有www.zixuephp.com 网站声明:本站所有视频,教程都由网友上传,站长收集和分享给大家学习使用,如由牵扯版权问题请联系站长邮箱904561283@qq.com
添加评论 |