MybatisPlus中凭什么可以使用Lambda来构建语句?

mybatisplus中凭什么可以使用Lambda来构建语句?

本文主要讲解两个内容

  1. mybatisplus中Lambda构建语句的时候是怎么通过方法引用得到相关表字段的。
  2. java序列化中的一些内置方法(扩展知道的可以略过)
  3. 通过方法引用得到其方法名称
  4. 源码中是如何实现的的

问题引入

熟悉mybatisplus的小伙伴应该清楚 可以使用Lambda来构建查询、更新语句,举个栗子

	@Data
    @TableName("user") //表名
    class User{
   
        private String name;
        private String password;
        private Integer age;
        private String email;
    }

new LambdaQueryWrapper<User>().eq(User::getAge, 1);

上述代码的意义是 构建查询user表中 age=1的用户,这里有个问题是我们传入的是一个方法引用为什么可以得到 'age’这个字段。

如果我们传的是一个class对象那我们可以通过下面的代码来得到具体的字段名。

Method getAge = user.getClass().getDeclaredMethod("getAge");
getAge.getName().substring(3).toLowerCase()

那如果是一个方法引用该如何获取到方法的名称呢?

可以通过 SerializedLambda 去获取函数的名称 可以看到在成员变量中有一个functionalInterfaceMethodName,他就保存了方法引用的函数名,通过注释可以了解到可以通过 writeReplace方法得到。那么writeReplace又是什么呢?

/**
Lambda 表达式的序列化形式。此类的属性表示 Lambda 工厂站点中存在的信息,包括静态元工厂参数(例如主功能接口方法的标识和实现方法的标识)以及动态元工厂参数(例如在捕获 Lambda 时从词法范围捕获的值)。
SerializedLambda 的实现者(例如编译器或语言运行时库)应确保实例正确反序列化。实现此目的的一种方法是确保writeReplace方法返回SerializedLambda的实例,而不是允许默认序列化继续进行。
SerializedLambda有一个readResolve方法,该方法在捕获类中查找名为$deserializeLambda$(SerializedLambda)的(可能是私有的)静态方法,将其自身作为第一个参数来调用,并返回结果。实现$deserializeLambda$的 Lambda 类负责验证SerializedLambda的属性是否与该类实际捕获的 lambda 一致。
通过反序列化序列化形式生成的函数对象的身份是不可预测的,因此身份敏感的操作(例如引用相等,对象锁定和System.identityHashCode()可能会在不同的实现中产生不同的结果,甚至在同一实现中的不同反序列化时也会产生不同的结果。
*/
public final class SerializedLambda implements Serializable {
   
    @java.io.Serial
    private static final long serialVersionUID = 8025925345765570181L;
    /**
     * The capturing class.
     */
    private final Class<?> capturingClass;
    /**
     * The functional interface class.
     */
    private final String functionalInterfaceClass;
    /**
     * The functional interface method name.
     */
    private final String functionalInterfaceMethodName;
    /**
     * The functional interface method signature.
     */
    private final String functionalInterfaceMethodSignature;
    /**
     * The implementation class.
     */
    private final String implClass;
    /**
     * The implementation method name.
     */
    private final String implMethodName;
    /**
     * The implementation method signature.
     */
    private final String implMethodSignature;
    /**
     * The implementation method kind.
     */
    private final int implMethodKind;
    /**
     * The instantiated method type.
     */
    private final String instantiatedMethodType;
    /**
     * The captured arguments.
     */
    @SuppressWarnings("serial") // Not statically typed as Serializable
    private final Object[] capturedArgs;

上面的注释是我直接翻译源码中的注释,可能会不通顺。但是我们可以翻译后的注释和类变量得到一些有用的信息

  1. SerializedLambda 是用来保存Lambda表达式的序列化形式会去保存具体的实现方法名称(implMethodName字段)
  2. 要实现Serializable接口,因为必须实现Serializable接口,jvm才会调用writeReplace。
  3. writeReplace的实现是由编译器或语言运行时库来完成的,也就是说只要是Lambda并且是继承了Serializable接口就可以调用对象的writeReplace方法返回一个SerializedLambda 对象。

java序列化

大家知道java对象要进行网络传输或者本地储存就必须要实现Serializable接口,Serializable接口没有方法或字段,仅用于标识可序列化的语义。但是在jvm内部会调用几个特殊的方法来完成java对象的序列化,打开Serializable的源码在注释上会有这样一段话

/**
 * Serializability of a class is enabled by the class implementing the
 * java.io.Serializable interface. Classes that do not implement this
 * interface will not have any of their state serialized or
 * deserialized.  All subtypes of a serializable class are themselves
 * serializable.  The serialization interface has no methods or fields
 * and serves only to identify the semantics of being serializable. <p>
 *
 * To allow subtypes of non-serializable classes to be serialized, the
 * subtype may assume responsibility for saving and restoring the
 * state of the supertype's public, protected, and (if accessible)
 * package fields.  The subtype may assume this responsibility only if
 * the class it extends has an accessible no-arg constructor to
 * initialize the class's state.  It is an error to declare a class
 * Serializable if this is not the case.  The error will be detected at
 * runtime. <p>
 *
 * During deserialization, the fields of non-serializable classes will
 * be initialized using the public or protected no-arg constructor of
 * the class.  A no-arg constructor must be accessible to the subclass
 * that is serializable.  The fields of serializable subclasses will
 * be restored from the stream. <p>
 *
 * When traversing a graph, an object may be encountered that does not
 * support the Serializable interface. In this case the
 * NotSerializableException will be thrown and will identify the class
 * of the non-serializable object. <p>
 *
 * Classes that require special handling during the serialization and
 * deserialization process must implement special methods with these exact
 * signatures:
 *
 * <PRE>
 * private void writeObject(java.io.ObjectOutputStream out)
 *     throws IOException
 * private void readObject(java.io.ObjectInputStream in)
 *     throws IOException, ClassNotFoundException;
 * private void readObjectNoData()
 *     throws ObjectStreamException;
 * </PRE>
 *
 * <p>The writeObject method is responsible for writing the state of the
 * object for its particular class so that the corresponding
 * readObject method can restore it.  The default mechanism for saving
 * the Object's fields can be invoked by calling
 * out.defaultWriteObject. The method does not need to concern
 * itself with the state belonging to its superclasses or subclasses.
 * State is saved by writing the individual fields to the
 * ObjectOutputStream using the writeObject method or by using the
 * methods for primitive data types supported by Dat
  • 25
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值