From the Java bytecode analysis of what I learned

Arguments and parameters

public int sum(int x,int y) {
	return x+y;
}

sum(2,3);
复制代码

Code above sum () method of the x, y is the parameter, the method invokes sum (2,3) 2 and 3 is the argument. Parameter in the method definition stage, but the argument is really a method call stage.

View bytecode

The basic parameters of the type of call

private static int intStatic = 222;

public static void main(String[] args) {
    method(intStatic);
    System.out.println(intStatic);
}

public static void method(int intStatic) {
    intStatic = 777;
}

复制代码

Bytecode above method () method ( javap -verbose XXX.class) as follows:

public static void method(int);
  descriptor: (I)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=1, locals=1, args_size=1
       0: sipush        777
       3: istore_0
       4: return
    LineNumberTable:
      line 13: 0
      line 14: 4
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       5     0 intStatic   I
复制代码

sipush: shaping a short constant value to the stack pushed

The form -1-5 iconst int stack bipush push one-byte shows a constant value (-128-127) to the stack pushed sipush represents a short integer constant value (-32768-32767) are pushed to stack

istore_0: The top of the stack int type value into a local variable first.

The above means that the byte code 777 is pushed to the stack, and then assign it to the local variable intStatic. So the results of our output is 222, because the assignment () method is the assignment of a local variable, does not change the value of the static variable, which is the Java variable of the principle of proximity, of course, can be used in such a way Class.intStatic display statement .

Immutable object parameter called

private static String stringStatic = "old string";

public static void main(String[] args) {
    method(stringStatic);
    System.out.println(stringStatic);
}
public static void method(String stringStatic) {
    stringStatic = "new string";
}

复制代码

The above results are output old string, the same look decompile bytecode

Constant pool:
  #6 = String     #35          // new string
  #7 = String     #36          // old string
  #10 = Utf8      stringStatic
  #35 = Utf8      new string
  #36 = Utf8      old string

public static void method(java.lang.String);
  descriptor: (Ljava/lang/String;)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=1, locals=1, args_size=1
       0: ldc           #6       // String new string
       2: astore_0
       3: return
    LocalVariableTable:
        Start  Length  Slot     Name             Signature
          0      4      0    stringStatic   Ljava/lang/String;
复制代码

ldc: The int, float, or a String constant value from the constant pool are pushed to the stack. astore_0: The top of the stack-type reference value stored in the first local variable.

It means that the byte code value # 6 (reference symbol) pushed to the stack, and assigning that value to the first reference type local variable (stringStatic).

Here you can see # 6 represents the data type is a String, which points to a constant pool CONSTANT_Utf8_info (abbreviation Utf8, Class method field file needs to be referenced to describe the so name) type, this constant represents the class (or interface) the fully qualified name, running time, the JVM based on the fully qualified name of the instance of the class, references to symbols that time is converted to a direct reference (the address is in memory).

Runtime constant pool

The above has been said constant pool, then the constant pool in the end is what stuff?

We all know that the method area and the Java heap, as each thread is a shared memory area, which is used to store class information has been loaded in the virtual machine, constants, static variables, the time compiler to compile code. Class file versions in addition to the classes, fields, methods, and interface description information, there is a constant pool (Constant Pool Table), and for storing various literal reference symbol generated compile, this part will after loading into the operating method of the class time constant pool storage area. Another important feature of the runtime constant pool file relative to Class constant pool is equipped dynamic, Java language does not require constant necessarily produce only compiler, that is not preset the content Class file constant pool to enter the zone method runtime constant pool can also be the new constants into the pool during the operation, String.intern () method is a typical representative.

Generation and permanent method area, a lot of people will be confused. The method area is JVM specification, merely substituting permanently achieved. JDK7 start from constant pool has been moved from the stack to the method area

Text string, declared as a final constant value are literal, and the symbol references a fully qualified name of the following three classes and interfaces constants 1. 2. The field names and descriptors 3. The method of descriptors and name

Constant pool:
  #1 = Methodref    #9.#28     // java/lang/Object."<init>":()V
  #2 = Fieldref     #8.#29     // com/generalthink/kafka/ParamDemo.stringStatic:Ljava/lang/String;
  #3 = Methodref    #8.#30     // com/generalthink/kafka/ParamDemo.method:(Ljava/lang/String;)V
  #8 = Class        #37        // com/generalthink/kafka/ParamDemo
复制代码

Therefore, the compiler symbol references stringStatic and literal old string will be added to the constant pool Class file, and then type the loading phase, the two constants will enter the runtime constant pool.

Object variable parameter called

The above parameters passed are immutable objects, here again become our next target variable analysis

private static StringBuilder stringBuilderStatic = new StringBuilder("old stringBuilder");

public static void main(String[] args) {
    method(stringBuilderStatic);
    System.out.println(stringBuilderStatic);
}

public static void method(StringBuilder stringBuilderStaticParam) {
    stringBuilderStaticParam.append(" first append");

    stringBuilderStaticParam = new StringBuilder("new stringBuilder");
    stringBuilderStaticParam.append(" new method's append");
}
复制代码

View keywords corresponding code section as follows:

Constant pool:
  #6 = String     #41            //  first append
  #8 = Class      #43            // java/lang/StringBuilder
  #9 = String     #44            // new stringBuilder
  #11 = String    #46            // new method's append
  #12 = String    #47            // old stringBuilder
  #15 = Utf8      stringBuilderStatic
  #30 = Utf8      stringBuilderStaticParam
  #41 = Utf8      first append
  #43 = Utf8      java/lang/StringBuilder
  #44 = Utf8      new stringBuilder
  #46 = Utf8      new method's append
  #47 = Utf8      old stringBuilder

public static void method(java.lang.StringBuilder);
  descriptor: (Ljava/lang/StringBuilder;)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=3, locals=1, args_size=1
       0: aload_0
       1: ldc           #6    // String  first append
       3: invokevirtual #7    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
       6: pop
       7: new           #8    // class java/lang/StringBuilder
      10: dup
      11: ldc           #9    // String new stringBuilder
      13: invokespecial #10   // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
      16: astore_0
      17: aload_0
      18: ldc           #11   // String new method's append
      20: invokevirtual #7    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      23: pop
      24: return
    LocalVariableTable:
      Start  Length  	Slot  		Name   						Signature
        0      25      0 		stringBuilderStaticParam   Ljava/lang/StringBuilder;
复制代码

aload_0: The first local reference type variable pushed to the stack. ldc: The int, float, or a String constant value from the constant pool are pushed to the stack. invokevirtual: Some examples for invoking methods require special handling, including instance initialization method, and a parent private methods Method pop: pop the top of the stack value (not a long or double type) new: create an object, and a reference value onto stack dup: replication and copy the value of the stack values ​​onto the stack astore_0: the top of the stack a first reference value in a local type variable return: return void from the current methods

Note that the aload_0 0 refers to LocalVariableTablethe slot 0 of the parameter, referred to herein as the stringBuilderStaticParam. It is to refer to a static variable is assigned to the local variable table virtual machine stack frame.

The above means that bytecode stringBuilderStaticParam pushed to the stack, and then pushing the first append a constant value to the stack, the method calls StringBuilder.append results obtained, and finally the stack. Then a new StringBuilder, a copy of the return address onto stack, then this address into stringBuilderStaticParam. Aload then re-stack the operation (the value here has been the overwriting, subsequent append operation for a static variable of the class stringBuilderStaticParam stringBuilderStatic nothing), then followed by calling the append method, and finally returns void.

Note that stringBuilderStatic just a pointer to a pointer to a specific address in memory only, it is not the memory address. java spec declared that everything in java is passed by value , this stuff never passed by reference code is the sole criterion for testing finishing, now assumed to be passed by reference, then the execution method after method, the result should be the output new stringBuilder new method's append, but the result is not output, so the argument passed is passed by value, this value is a pointer to the object only.

How this is done

int m = 1;
public static void main(String[] args) {
    ParamDemo demo = new ParamDemo();
    System.out.println(demo.method());
}
public  int method() {
    return m + 1;
}
复制代码

We call method () method in the m, here implicitly uses this, in fact, is this.m. So how this formula to achieve it?

public int method();
  descriptor: ()I
  flags: ACC_PUBLIC
  Code:
    stack=2, locals=1, args_size=1
       0: aload_0
       1: getfield      #2     // Field m:I
       4: iconst_1
       5: iadd
       6: ireturn
    LineNumberTable:
      line 15: 0
    LocalVariableTable:
      Start  Length  Slot  Name   Signature
          0       7     0  this   Lcom/generalthink/kafka/ParamDemo;
}
复制代码

We LocalVariableTable can be found this to be an argument, its implementation is so simple, Javac compiler compile time to visit this keyword into a common access method parameters, then automatically invoked when a virtual machine instance method this parameter is passed.

When it comes to this certainly think of super, super is actually an ordinary method call, implemented by invokespecial instructions.

String.intern () principle

When using intern () method you think is the role of the dynamic method of adding running literal constants pool. If the runtime constant pool of the same string already exists (the equals method determination), the object pool is returned, otherwise the corresponding reference after it is added to the constant pool.

String s1 = "Hello";
String s2 = new String("Hello").intern();

//true
System.out.println(s1 == s2);
复制代码

The output is true, during compilation "Hello" the literal has been added to the constant pool, during operation, called intern () method, is determined to equal two strings according to the equals method, which then returns a reference constant pool of addresses Hello, so in this case s1, s2 in fact pointing to the same address.

We will modify the code to do something

String s1 = "Hello";
String s2 = "World";

String s3 = s1 + s2;

String s4 = "Hello" + "World";

System.out.println(s3 == s4);

System.out.println(s3.intern() == s4);

复制代码

The results are output to false and true. We note that most of the different s3 and s4 is, s3 is obtained by adding a variable, the same view bytecode

#2 = String     #37     // Hello
#3 = String     #38     // World
#4 = Class      #39     // java/lang/StringBuilder
#5 = Methodref  #4.#36  // java/lang/StringBuilder."<init>":()V
#6 = Methodref  #4.#40  // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#7 = Methodref  #4.#41  // java/lang/StringBuilder.toString:()Ljava/lang/String;
#8 = String     #42     // HelloWorld

public static void main(java.lang.String[]);
  descriptor: ([Ljava/lang/String;)V
  flags: ACC_PUBLIC, ACC_STATIC
  Code:
    stack=3, locals=5, args_size=1
      0: ldc           #2        // String Hello
      2: astore_1
      3: ldc           #3        // String World
      5: astore_2
      6: new           #4        // class java/lang/StringBuilder
      9: dup
      10: invokespecial #5        // Method java/lang/StringBuilder."<init>":()V
      13: aload_1
      14: invokevirtual #6        // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      17: aload_2
      18: invokevirtual #6        // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
      21: invokevirtual #7        // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
      24: astore_3
      25: ldc           #8        // String HelloWorld
      27: astore        4
      ...
复制代码

It can be seen from the bytecode actually called StringBuilder.Append s3 () method to get, the value of s4 can be directly determined at compile time, it is an accurate value, so in this case the constant pool HelloWorld in it existed.

Guess you like

Origin juejin.im/post/5d4cd6b0e51d4561ba48fdaa