方法引用获取字段名称

795 阅读1分钟

方法引用获取字段名称

引言:

此段需要lambda和函数时接口知识,不了解的可以去补充下哦

在使用Mybatis-Plus的LambdaQueryWrapper时,经常会看到下面这段代码:

wrapper.ge(User::getInfo,"xxx");

我们都知道ge()方法第一个参数是字段名称,那么在java中是如何通过方法引用获取到字段名称的呢?

SerializedLambda类

Java8 lambda函数接口如果继承了Serializable这个接口,那么把lambda函数的实例对象序列化成字节,然后再使用ObjectInputStream反序列化成一个对象,此时反序列化获得的对象是SerializedLambda类型的一个实例。

关键类在于SerializedLambda,此类实现了Serializable接口

// 源码
public final class SerializedLambda implements Serializable

比如 User::getInfo 这个 lambda 表达式,底层接收的函数接口是继承了 Serializable接口的话,比如Mybatis-plusSFunction函数接口。

每次传入User::getInfo这个方法引用作为参数给SFunction接口时,底层都是创建一个SFunction的实例对象,这个对象封装了对User的getInfo方法的调用。

测试

创建自定义函数式接口

@FunctionalInterface
public interface IGetter<T,R> extends Serializable {
    R get(T source);
}

创建Java Bean

public class User {
    private Long id;
    private String info;
    private String query;
    
    // ...getter setter省略
}

测试

public class Test {
    public static void main(String[] args) {
        IGetter<User, String> fn = User::getQuery;
        try {
            Method method = fn.getClass().getDeclaredMethod("writeReplace");
            method.setAccessible(true);
            SerializedLambda lambda = (SerializedLambda) method.invoke(fn);
            System.out.println("lambda.getImplClass() = " + lambda.getImplClass());
            System.out.println("lambda.getImplMethodName() = " + lambda.getImplMethodName());
        } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

输出

image.png

得到方法名称之后,只需提取字段名称即可