@FunctionalInterface
public interface MyFunctionextends Function,Serializable{
}
public static void main(String[] args)throws IOException, ClassNotFoundException {
//第一种
String dd =map((Function&Serializable) T::aa, "dd");
System.out.println("result~~~~~~~"+dd);
//第二种 在方法指定是序列化函数
String yy =map1(T::aa, "dd");
System.out.println("result~~~~~~~"+yy);
}
public static Stringaa(String pa){
System.out.println(pa);
return pa +"~~~~~";
}
static <U> U map(Function<String, ?extends U> function,String a)throws IOException, ClassNotFoundException {
System.out.println(function);
serialize(function, new FileOutputStream("lambda.obj"));
Function func = (Function)deserialize(new FileInputStream("lambda.obj"));
U apply = func.apply(a);
System.out.println(apply);
return apply;
}
static U map1(MyFunction function,String a)throws IOException, ClassNotFoundException {
System.out.println(function);
serialize(function, new FileOutputStream("lambda.obj"));
Function func = (Function)deserialize(new FileInputStream("lambda.obj"));
U apply = func.apply(a);
System.out.println(apply);
return apply;
}
public static void serialize(Object obj, OutputStream out)throws IOException {
ObjectOutputStream objOut =new ObjectOutputStream(out);
objOut.writeObject(obj);
out.flush();
out.close();
}
public static Objectdeserialize(InputStream in)throws IOException, ClassNotFoundException {
ObjectInputStream objIn =new ObjectInputStream(in);
Object result = objIn.readObject();
objIn.close();
return result;
}
2. lambda序列化
如果我们使用这个命令运行TestLambda:java -cp . -Djdk.internal.lambda.dumpProxyClasses=. TestLambda
程序运行完成后,会在当前目录生成两个class文件,TestLambda\$$Lambda$1.class和TestLambda\$$Lambda$4.class。
writeReplace方法的作用是在该类实例序列化时,并不会真正序列化该类的对象,而是将writeReplace方法返回的对象进行序列化。所以,lambda对象序列化的时候,真正序列化的对象是SerializedLambda对象。
该SerializedLambda对象记录如下信息:
(1).lambda定义所在的Class对象
(2).lambda实现的函数式接口的全限定名
(3).lambda实现的函数式接口的方法名
(4).lambda实现的函数式接口的方法签名
(5).implMethodKind(这个含义我也没弄明白)
(6).lambda函数的真正实现方法所在的类名,和(1)中的Class对象相同,这里是类的全限定名
(7).lambda函数的真正实现方法的方法名
(8).lambda函数的真正实现方法的方法签名
(9).替换类型参数的函数式接口方法签名
(10).捕获的参数
最终,这些信息,也就是上面代码中new SerializedLambda对象传进去的参数,才是被序列化记录的信息,这些信息都是在用于lambda的反序列化。
3.lambda反序列化
既然lambda序列化时记录的是SerializedLambda对象,那么我们来看SerializedLambda对象是怎么最终变成lambda对象的。
在SerializedLambda类的源码中,我们可以看到有一个方法readResolve,这个方法的作用是在该类对象被反序列化时,将调用readResolve方法,该方法的返回对象才是反序列化返回的对象。
从代码中可以看出,反序列化SerializedLambda对象时,readResolve方法将会从capturingClass中寻找名为"$deserializeLambda$"的方法。由上一节可知,capturingClass就是定义lambda对象所在的类对象,而$deserializeLambda$方法也是编译器生成的隐藏方法,通过 javap -s -p -v -c -l TestLambda.class 查看字节码,可以看到确实存在方法$deserializeLambda$。
由于这个方法字节码比较长,就不全部贴出来分析了,在这个方法中,会对上一节序列化记录的信息进行校验,校验正确,程序会调用invokeDynamic指令生成代表lambda的内部类,并且创建该内部类的对象,然后返回作为反序列化的最终对象。
简单来说,lambda对象的反序列化,就是先反序列化出SerializedLambda对象,然后调用readResolve方法生成真正的lambda对象。
4.总结
(1).编译器会在定义lambda函数的类中,生成静态方法$deserializeLambda$(java.lang.invoke.SerializedLambda),该方法知晓由SerializedLambda对象生成lambda对象的具体细节。
(2).lambda对象运行时生成的类,它有一个writeReplace方法,该方法将lambda的信息记录在一个SerializedLambda对象中,然后将这个SerializedLambda对象序列化。它记录了定义lambda所在的类,lambda实现的函数式接口等。
(3).SerializedLambda对象定义的readResolve方法,就是用于反序列化生成lambda对象的。
(4).lambda对象序列化整个流程:
lambda对象 --> writeReplace方法 --> SerializedLambda对象 --> 序列化的字节 --> SerializedLambda对象 --> readResolve方法 --> $deserializeLambda$方法 --> lambda对象。