Final parameters/Variables in Java + bytecode analysis of anonymous inner classes, and use of Java 8 __java

Source: Internet
Author: User
Tags field table

One common sense before Java 8 is that if you want to define an anonymous inner class in a method and use local variables (including parameters) within that method, you need to use the final keyword modification. There are many interpretations and explanations of this mechanism on the Internet, but most of them are an abstract understanding. If you can analyze the bytecode, the problem is clear.


The obvious fact is that local variables (called variable a) are stored in the local variable table (reference or base type) of the stack frame, where the method of defining the anonymous inner class is called method a, the method of using this local variable in the anonymous inner class (called method B is compiled and stored in the method table of the class file, and the method body is saved in the Code property. The runtime passes a class load, and validation is stored in the method area. In executing an anonymous inner class, the JVM creates a stack frame of method B. It is obviously not directly related to the stack frame of method A, even when method B is executed, method A's stack frame has been reclaimed, how does the JVM ensure that method B can correctly use the value pointed to by variable a?


Let's look at bytecode to see how the Java compiler and JVM do this, based on Oracle JDK8 compilation; 1. Bytecode Analysis:

Peripheral class : Finalparameter

Defines an anonymous inner class derived from a, which uses the method testfinal the local variable A and the parameter bytes;

Public final class Finalparameter {
    interface A {
        void Test ();
    }
    private void Testfinal (final byte[] bytes) {
        final int a = ten;
        New A () {
            @Override public
            Void Test () {
                System.out.println (A + "" + bytes.length);
        }
    }
}

According to the internal class naming rules we know that the class name of this anonymous inner class is finalparameter$1; use Javap-verbose finalparameter$1 to view the byte code of the class, and in a UNIX environment be careful not to forget to escape "$".

I intercepted the Field table section:

  final int val$a;
    Descriptor:i
    flags:acc_final, acc_synthetic

  FINAL byte[] val$bytes;
    Descriptor: [B
    flags:acc_final, acc_synthetic

  FINAL com.jvm.showByteCode.FinalParameter this$0;
    Descriptor:lcom/jvm/showbytecode/finalparameter;
    Flags:acc_final, Acc_synthetic

You can see that the compiler added 3 fields for us, respectively:

val$a,val$bytes,this$0;

Where this$0 is a reference to an instance of a peripheral class object, the first two are generated from the local variables bytes and a of the outer class method, and they are final.

Let's look at the <init> () method of the Finalparameter$1 class:

Descriptor:

Descriptor: (lcom/jvm/showbytecode/finalparameter;i[b) V

Code attribute (method implementation):

Code:
      stack=2, locals=4, args_size=4
         0:aload_0
         1:aload_1
         2:putfield      #1                  //Field this$0: Lcom/jvm/showbytecode/finalparameter;
         5:aload_0
         6:iload_2
         7:putfield      #2                  //Field val$a:i
        10:aload_0
        11:aload_3
        12: Putfield      #3                  //Field val$bytes:[b
        15:aload_0
        16:invokespecial #4                  //Method java/lang/ Object. " <init> ":() V
        19:return

Part of the Testfinal method in the perimeter class that calls the anonymous inner class:

10:invokespecial #3                  //Method com/jvm/showbytecode/finalparameter$1. " <init> ":(lcom/jvm/showbytecode/finalparameter;i[b) V

Here we can clearly see the following facts:

(1) The <init> method has 4 parameters, the first of which is this, and the other three different types are finalparameter,int,byte arrays respectively;

(2) Their parameters are assigned to the corresponding final field (this$0,val$a,val$bytes);

(3) The outer class refers to the current instance object, a value, and the bytes array reference to the Finalparameter$1 <init> () method;


Therefore, we can know that local variables that use the Outer class method in an anonymous inner class are actually final member variables that use the corresponding value (reference).

The internal class uses a copy of the local variable, so if you want to semantically guarantee the consistency of local variables and replicas, you should use final to ensure that the local variable remains unchanged.


2. Java 8 "Improvement": the next section of code passed the JDK8 based compilation, but if the annotation is removed, still can not compile, it seems only in the wording of the "labor". That is to say, the design idea of using local variables for internal classes in Java also guarantees that these two variables (one is local variables, it is a member variable of the inner class; If you do not want to guarantee such consistency, I think you can have the following scenario: (1) You can create an abstract class, add a constructor, Passing the value of a local variable through the constructor (2) writing a factory method (or factory Class), local variable incoming factory method (the corresponding parameter of the factory method is final) returns an internal class instance; So you don't have to set the local variable to final; The Java design team's design idea is that programmers use local variables in their inner classes, which should imply that two variables should be consistent.

private void testfinal (byte[] bytes) {
        int a = ten;
        New A () {
            @Override public
            Void Test () {
                System.out.println (A + "" + bytes.length);
            }
        };        a = one;        bytes = null;
    }






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.