Java 8 supports dynamic languages, sees cool lambda expressions, and Java, which has always been a static type language, and lets people see the goal that a Java virtual machine can support a dynamic language.
Import Java.util.function.consumer;public class Lambda {public static void main (string[] args) {consumer<string> c = S-System.out.println (s); C.accept ("Hello lambda!");}}
Just seeing this expression, it feels like Java is handled in a way that is an anonymous class inside.
public class Lambda {static {System.setproperty ("jdk.internal.lambda.dumpProxyClasses", ".");} public static void Main (string[] args) {consumer<string> C = new consumer<string> () {@Overridepublic void acce PT (String s) {System.out.println (s);}}; C.accept ("Hello Lambda");}}
The result of the compilation should be Lambda.class, Lambda$1.class guess in support of dynamic language Java in the same time, in the final compilation of the generation of our common way.
But that's not the result, it's just a lambda.class.
Decompile it, to see what the truth is?
Note-P This parameter-p parameter shows all methods without the default is not to decompile the private method.
public Lambda (); Descriptor: () V flags:acc_public code:stack=1, Locals=1, args_size=1 0:aload_0 1:invokespec ial #21//Method java/lang/object. " <init> ":() V 4:return linenumbertable:line 3:0 localvariabletable:start Length Slot Name Signature 0 5 0 this llambda; public static void Main (java.lang.string[]); Descriptor: ([ljava/lang/string;) V flags:acc_public, Acc_static code:stack=2, locals=2, args_size=1 0 : Invokedynamic #30, 0//invokedynamic #0: Accept: () Ljava/util/function/consumer; 5:astore_1 6:aload_1 7:LDC #31//String Hello Lambda 9:invokeinterf Ace #33, 2//Interfacemethod java/util/function/consumer.accept: (ljava/lang/object;) V 14:return L Inenumbertable:line 8:0 line 9:6 line 10:14 localvariabletable: Start Length Slot Name Signature 0 0 args [ljava/lang/string; 6 9 1 C Ljava/util/function/consumer; Localvariabletypetable:start Length Slot Name Signature 6 9 1 C ljava/util/functio n/consumer<ljava/lang/string;>; private static void Lambda$0 (java.lang.String); Descriptor: (ljava/lang/string;) V flags:acc_private, acc_static, Acc_synthetic code:stack=2, Locals=1, args_s ize=1 0:getstatic #46//Field Java/lang/system.out:ljava/io/printstream; 3:aload_0 4:invokevirtual #50//Method java/io/printstream.println: (ljava/lang/string;) V 7:return linenumbertable:line 8:0 localvariabletable:start Length Slot Name Signature 0 8 0 S ljava/lang/string;} SourceFile: "Lambda.java" bootstrapmethods:0: #66 invokestatic Java/lang/invoke/lambdametaFactory.metafactory: (ljava/lang/invoke/methodhandles$lookup; ljava/lang/string; Ljava/lang/invoke/methodtype; Ljava/lang/invoke/methodtype; Ljava/lang/invoke/methodhandle; Ljava/lang/invoke/methodtype;) Ljava/lang/invoke/callsite; Method arguments: #67 (ljava/lang/object;) v #70 invokestatic lambda.lambda$0: (ljava/lang/string;) v #71 (lja va/lang/string;) vinnerclasses:public static Final #77 = #73 of #75; Lookup=class Java/lang/invoke/methodhandles$lookup of Class Java/lang/invoke/methodhandles
Here we find a few places that are not quite the same as our common Java, because the constants are defined too much, the article does not post the
1. invokedynamic directive
The four directives of the Java calling function (Invokevirtual, invokespecial, Invokestatic, invokeinterface), usually the symbolic reference of a method can be generated when the static type language is compiled. While the dynamic type language can only determine the receiver type at runtime, changing the semantics of the four directives has a great impact on the Java version, so the JSR 292 "supporting dynamically Typed Languages on the Java Platform" Added a new directive
Invokedynamic
0:invokedynamic #30, 0 //invokedynamic #0: Accept: () Ljava/util/function/consumer;
The #30 represents the constant #30 that is the comment invokedynamic #0: Accept: () Ljava/util/function/consumer;
0 is a placeholder symbol that is currently useless
2. Bootstrapmethods Each instance of a invokedynamic instruction is called a dynamic call site, and the dynamic call point is the first
Not linked status(unlinked: means that the call point is not specified yet), the dynamic call point relies on the Bootstrap method to link to the specific method. The boot method is generated by the compiler and, at runtime, when the JVM encounters the invokedynamic instruction for the first time, it invokes the Bootstrap method to link the name (method name, method signature) specified by the invokedynamic instruction with the specific execution code (the target method). The return value of the Bootstrap method permanently determines the behavior of the calling point. The return value type of the Bootstrap method is Java.lang.invoke.CallSite, and a invokedynamic directive associates a CallSite, Delegate all calls to Callsite current target (Methodhandle)
Invokedynamic #0 is where bootstrapmethods represents #0.
0: #66 invokestatic java/lang/invoke/lambdametafactory.metafactory: (ljava/lang/invoke/methodhandles$lookup; ljava/lang/string; Ljava/lang/invoke/methodtype; Ljava/lang/invoke/methodtype; Ljava/lang/invoke/methodhandle; Ljava/lang/invoke/methodtype;) Ljava/lang/invoke/callsite; Method arguments: #67 (ljava/lang/object;) v #70 invokestatic lambda.lambda$0: (ljava/lang/string;) v #71 (ljava/lang/string;) V
We see a method called Lambdametafactory.metafactory.
Parameters:
Lambdametafactory.metafactory (Lookup, String, Methodtype, Methodtype, Methodhandle, Methodtype) have six parameters, which are described in order as follows
1. Methodhandles.lookup Caller: Represents the lookup context and the caller's access, the JVM automatically populates this parameter when using the invokedynamic directive
2. String Invokedname: The name of the method to be implemented, when using invokedynamic, the JVM automatically fills us (the content is populated from the constant pool InvokeDynamic.NameAndType.Name), Here the JVM fills us up as "apply", which is the Consumer.accept method name.
3. Methodtype Invokedtype: The type of method parameter that the calling point expects and the type of the return value (method signature). When using the invokedynamic directive, the JVM automatically populates this parameter (populated from the constant pool InvokeDynamic.NameAndType.Type), where the argument is string, the return value type is consumer, The parameter that represents the target method for this call point is string, and then Invokedynamic returns a consumer instance after execution.
4. Methodtype Sammethodtype: The type of interface method that the function object will implement, where the value is (object) object, which is the type of the Consumer.accept method (the generic information is erased). #67 (ljava/lang/ Object;) V
5. Methodhandle Implmethod: A direct method handle (Directmethodhandle) that describes the specific implementation method that will be executed at the time of invocation (including the appropriate parameter adaptation, return type adaptation, and attaching the parameters captured before calling the parameter), where #70 invokestatic lambda.lambda$0: The method handle of the (ljava/lang/string;) V method.
6. Methodtype Instantiatedmethodtype: The function interface method replaces the generic as the type of the method, usually the same as Sammethodtype, where the different cases are generic:
For example, the function interface method is defined as void accept (T T) t as a generic identity, at this time the method type is (object) void, at compile-time t is determined, that is, T is replaced by a string, then Sammethodtype is (object) void, and Inst Antiatedmethodtype is (String) Void.
4th, 5, 63 parameters are from the class file. As in the boot method above, the three parameters in the byte code arguments are applied to the 4, 5, 6 parameters.
Method arguments: #67 (ljava/lang/object;) v #70 invokestatic lambda.lambda$0: (ljava/lang/string;) v #71 (ljava/lang/string;) V
Let's look at the implementation code in Metafactory's method.
public static CallSite metafactory (methodhandles.lookup caller, String invokedname, methodtype Invokedtype, Methodtype Sammethodtype, Methodhandle Implmethod, methodtype instantiatedmethodtype) throws lambdaconversionexception { abstractvalidatinglambdametafactory MF; MF = new Innerclasslambdametafactory (caller, Invokedtype, invokedname, Sammethodtype, Implmethod, Instantiatedmethodtype, false, Empty_class_array, Empty_mt_array); Mf.validatemetafactoryargs (); return Mf.buildcallsite (); }
In the function of Buildcallsite
CallSite Buildcallsite () throws Lambdaconversionexception { final class<?> innerclass = Spininnerclass ();
The function Spininnerclass constructs this inner class, which generates an inner class such as a lambda$ $Lambda $1/716157500, which is built at run time and is not saved on disk, and if you want to see this constructed class, You can set the environment parameters by
System.setproperty ("Jdk.internal.lambda.dumpProxyClasses", ".");
will be in the path you specified. This inner class is generated on the current run path
3.Static Class
Java generates the Lambda$0 static private class when compiling the expression, and implements the method block System.out.println (s) in the expression in this class;
private static void Lambda$0 (java.lang.String); Descriptor: (ljava/lang/string;) V flags:acc_private, acc_static, acc_synthetic Code: stack=2, Locals=1 , args_size=1 0:getstatic #46 //Field Java/lang/system.out:ljava/io/printstream; 3:aload_0 4:invokevirtual #50 //Method java/io/printstream.println: (ljava/lang/string;) V 7:return linenumbertable: Line 8:0 localvariabletable: Start Length Slot Name Signature 0 8 0 s ljava/lang/string;
Of course the lambda$ $LAMBDA generated in the previous step by setting the Jdk.internal.lambda.dumpProxyClasses $1.class
public void accept (java.lang.Object); Descriptor: (ljava/lang/object;) V flags:acc_public Code: stack=1, locals=2, args_size=2 0:aload_1 1:checkcast #15 //class java/lang/string 4:invokestatic #21 //Method lambda.lambda$0: ( ljava/lang/string;) V 7:return runtimevisibleannotations: 0: #13 ()
Called the lambda.lambda$0 static function, which is the function block in the expression
Summarize
This completes the implementation of the lambda expression, using the invokedynamic Directive, The runtime calls the lambdametafactory.metafactory dynamically generated internal class, implements the interface, the inner class call method block is not generated dynamically, but in the original class has been compiled to generate a static method, the inner class only need to call the static method
Java 8 Dynamic Type language lambda expression implementation principle analysis