Java 是一种可以撰写跨平台应用软件的面向对象的程序设计语言. Java 技术具有卓越的通用性, 高效性, 平台移植性和安全性, 广泛应用于 PC, 数据中心, 游戏控制台, 科学超级计算机, 移动电话和互联网, 同时拥有全球最大的开发者专业社群.
给你学习路线: html-CSS-js-jq-javase - 数据库 - jsp-servlet-Struts2-hibernate-mybatis-spring4-springmvc-ssh-ssm
Java8 新增了 lambda 表达式, 最常见的用法是配合 Stream 做集合操作. 下面是一种类似彩蛋的东西可以妙用到某些场合.
一般用法, 比如下面这样
Optional.of(1L).ifPresent(number -> { System.out.println(number);});
或者简化成这样
Optional.of(1L).ifPresent(System.out::println);
有什么办法能获取到 System.out::println 里面的方法名字符串 String methodName = "println" ?
啥效果?
小编推荐一个学 Java 的学习裙[ 七六零, 二五零, 五四一 ] , 无论你是大牛还是小白, 是想转行还是想入行都可以来了解一起进步一起学习! 裙内有开发工具, 很多干货和技术资料分享!
执行代码
FnConverter fnConverter = new FnConverter<>();String fieldName = fnConverter.convertFnToString(Foo::getBar);System.out.println("方法名:"+fieldName);
输出
方法名: bar
怎么做?
第一步: 定义一个 FunctionalInterface (敲黑板, 画重点 extends Serializable )
/** * @author Frank */@FunctionalInterfacepublic interface Fn extends Serializable { Object apply(T source);}
第二布: 准备个类(酱油)
import lombok.Data;/** * @author liuyuyu */@Datapublic class Foo { private Integer bar;}
第三步: 获取 Fn 的信息的工具类
import java.beans.Introspector;import java.lang.invoke.SerializedLambda;import java.lang.reflect.Method;/** * @author Frank */public class Reflections { private Reflections() { } public static String fnToFieldName(Fn fn) { try { Method method = fn.getClass().getDeclaredMethod("writeReplace"); method.setAccessible(Boolean.TRUE); SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn); String getter = serializedLambda.getImplMethodName(); String fieldName = Introspector.decapitalize(getter.replace("get", "")); return fieldName; } catch (ReflectiveOperationException e) { throw new RuntimeException(e); } }}
画重点 SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
第四步: 写个梨子跑起来
- /** * @author liuyuyu */public class FnConverter { public String convertFnToString(Fn fn){ return Reflections.fnToFieldName(fn); } public static void main(String[] args) { FnConverter fnConverter = new FnConverter<>(); String fieldName = fnConverter.convertFnToString(Foo::getBar); System.out.println("方法名:"+fieldName); }}
- Run
方法名: bar
啥原理?
Serializable 是 Java 对象序列化的接口, 凡是实现这个接口(interface 是继承, 也算)Java 都要提供序列化和反序列化的方法( ObjectInputStream/ObjectOutputStream 可能会让你想起点什么).
但是 lambda 比较特殊, 它是一个方法, 可以认为是一个动作(或者说是功夫? 比如九阴真经), 没办法直接保存, Java 提供了 SerializedLambda 这个类保存 lambda 的信息.
public final class SerializedLambda implements Serializable { private static final long serialVersionUID = 8025925345765570181L; private final Class capturingClass; private final String functionalInterfaceClass; private final String functionalInterfaceMethodName; private final String functionalInterfaceMethodSignature; private final String implClass; private final String implMethodName; private final String implMethodSignature; private final int implMethodKind; private final String instantiatedMethodType; private final Object[] capturedArgs; // 省略之后代码}
小编推荐一个学 Java 的学习裙[ 七六零, 二五零, 五四一 ] , 无论你是大牛还是小白, 是想转行还是想入行都可以来了解一起进步一起学习! 裙内有开发工具, 很多干货和技术资料分享!
知道了这个隐藏 (彩) 特性(蛋), 我们回头看看刚才黑板上画的重点
@FunctionalInterface //lambdapublic interface Fn extends Serializable // 序列化接口
两个条件满足
因为这个东西是个隐藏 (彩) 特性(蛋), 我们不能直接获取到 SerializedLambda . 直接上反射!
SerializedLambda serializedLambda = (SerializedLambda) method.invoke(fn);
这样, 我们就可以获取到 lambda 的方法名
来源: http://www.jianshu.com/p/b4c8b7a90f9f