Java 8 Dynamic Type language lambda expression implementation principle analysis

Source: Internet
Author: User

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

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.