Arguments and parameters

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

sum(2.3);
Copy the code

In the code above, the x and y in the sum() method are the parameters, and the 2 and 3 in the call method sum(2,3) are the arguments. Parameters are in the method definition phase, while arguments are in the method invocation phase.

View bytecode

Basic type parameter 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;
}

Copy the code

The bytecode (javap-verbose xxx.class) of the method() method above is 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
Copy the code

Sipush: Pushes a short integer constant value to the top of the stack

Iconst pushes the int form -1-5 to the top of the stack. Bipush means that the constant value of a single byte (-128-127) is pushed to the top of the stack. Sipush means that a short integer constant value (-32768-32767) is pushed to the top of the stack

Istore_0: stores the top int value to the first local variable.

The bytecode above means pushing 777 to the top of the stack and assigning it to intStatic, a local variable. So the output is 222, because the assignment in method() is to a local variable and does not change the value of the static variable, which is Java’s nearest variable principle.

Immutable object parameter call

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";
}

Copy the code

The output above is old string, decompile again and look at the bytecode

Constant pool:
  #6 = String #35 // new string
  #7 = String #36 // old string
  #10 = Utf8 stringStatic
  #35 = Utf8 new string
  #36 = Utf8 old stringpublic 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;
Copy the code

LDC: Pushes int, float, or String constant values from the constant pool to the top of the stack. Astore_0: Stores the top of the stack reference value into the first local variable.

Bytecode means pushing the value of #6(symbolic reference) to the top of the stack, and then assigning its referential value to the first local variable (stringStatic).

You can see that #6 is a String that points to a CONSTANT_Utf8_info(Utf8) type in the constant pool. This constant represents the fully qualified name of the Class (or interface). At runtime, The JVM instantiates the class based on the fully qualified name, at which point symbolic references are converted to direct references (that is, addresses in memory).

Run-time constant pool

I’ve been talking about constant pools, but what exactly is a constant pool?

We all know that the method area, like the Java heap, is an area of memory shared by individual threads that stores information about classes that have been loaded by the virtual machine, constants, static variables, and just-in-time compiler compiled code. The Constant Pool Table is used to store various literals and symbolic references generated at compile time. This part of the Constant Table is stored in the runtime Constant Pool after the Class is loaded into the method area. Another important feature of the runtime constant pool over the Class file constant pool is its dynamic nature. The Java language does not require a constant to be generated only by the compiler, that is, the content not preset into the Class file constant pool can enter the method area runtime constant pool. New constants can also be pooled at run time, with the string.intern () method being a good example.

Permanent generation and method area, many people will be confused. The method area is the JVM specification, while the persistent generation is just the implementation. The constant pool has been moved from the method area to the heap since JDK7

Text strings, constants declared final are literals, and symbolic references contain three types of constants: 1. Fully qualified names of classes and interfaces 2. field names and descriptors 3. method names and descriptors

Constant pool:
  #1 = Methodref #9.#28 // java/lang/Object."
      
       ":()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
Copy the code

So, the compiler symbol reference to stringStatic and the literal Old String are added to the Class file’s constant pool, and then at Class load time, the two constants are added to the runtime constant pool.

Variable object argument call

The above parameter is passing immutable objects, so this becomes mutable objects and let’s look at it again

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");
}
Copy the code

View the key bytecode 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 stringBuilderpublic 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."
      
       ":(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;
Copy the code

Aload_0: Pushes the first reference type local variable to the top of the stack. LDC: Pushes int, float, or String constant values from the constant pool to the top of the stack. Invokevirtual: used to call instance methods that require special treatment, including instance initializer methods, private methods, and superclass methods. Create an object and push its reference value to the top of the stack. Dup: copies the top value and pushes the copy value to the top of the stack. Astore_0: stores the top reference value to the first local variable

Note that the 0 in aload_0 refers to the parameter with slot 0 in LocalVariableTable, in this case stringBuilderStaticParam. It assigns a reference to a static variable to a local variable table in the virtual machine stack frame.

The bytecode above means that stringBuilderStaticParam is pushed to the top of the stack, the first Append constant is pushed to the top of the stack, the stringBuilder. append method is called to get the result, and the stack is pushed out. Then new a StringBuilder, push a copy of the returned address to the top of the stack, and store that address to stringBuilderStaticParam. It then reaload to the top of the stack (the value has been overwritten, so subsequent append operations on stringBuilderStaticParam have nothing to do with the class’s static variable stringBuilderStatic), then calls the append method, and finally returns Void.

Notice that stringBuilderStatic is just a pointer, a pointer to an address in memory, it’s not the address in memory. Java Spec states that everything in Java is passed by value, there is no such thing as passed by reference, and code is the only criterion for checking collation. Now, assuming that method is passed by reference, the output should be New stringBuilder New Method’s Append, but the output is not, so parameter passing is value passing, and that value is just a pointer to the object.

How is this implemented

int m = 1;
public static void main(String[] args) {
    ParamDemo demo = new ParamDemo();
    System.out.println(demo.method());
}
public  int method(a) {
    return m + 1;
}
Copy the code

We call m in method(), which implicitly uses this, but this.m. So how is this implemented?

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;
}
Copy the code

In LocalVariableTable, we can see that this becomes a parameter. The implementation is as simple as this. The Javac compiler compiles the access to this keyword into a normal method parameter, which is then passed in automatically when the virtual machine calls the instance method.

Super is an ordinary method call, which is implemented with the Invokespecial command.

String.intern () principle

When using intern(), you should think of methods that dynamically add literals to the runtime constant pool. If the same string already exists in the constant pool at runtime (as determined by equals), the object in the pool is returned, otherwise the reference is returned after it is added to the constant pool.

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

//true
System.out.println(s1 == s2);
Copy the code

The value of “Hello” is added to the constant pool at compile time. At run time, the equals () method is called, and the value of s1 and s2 are referenced to the same address.

Let’s change the code a little bit

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);

Copy the code

The output is false and true, respectively. The main difference we notice between S3 and S4 is that S3 is the sum of variables, again looking at the bytecode

#2 = String #37 // Hello
#3 = String #38 // World
#4 = Class #39 // java/lang/StringBuilder
#5 = Methodref #4.#36 // java/lang/StringBuilder."
      
       ":()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."
      
       ":()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
      ...
Copy the code

As you can see from the bytecode, S3 is actually obtained by calling stringBuilder.append (), and s4’s value can be determined directly at compile time, which is an exact value, so HelloWorld exists in the constant pool.