Analyzing the invariance of Integer type parameter value to understand Java value parameter passing

Analyzing the invariance of Integer type parameter value to understand Java value parameter passing

Previously on java There are some doubts about the reference passing of value Integer and String The method is passed in to modify, but the final value is not modified. Now, after continuous learning, I have some new experience here. Now I summarize.

Code process

(1) Code first

private void add(Integer i) {
        i = i - 1;
    }

    private void reverse(String s) {
        s = "sey";
    }

    public static void main(String[] args) {
        Integer i = 1;
        String s = "yes";
        Test test = new Test();
        test.add(i);
        test.reverse(s);

        // Print value
        System.out.println(String.format("i Value of:%d", i));
        System.out.println(String.format("s Value of:%s", s));
    }

(2) The printing results are as follows:

You can see that the value has not changed. Next, let me analyze why.
(3) Decompile as follows:

public class Test
{

	public Test()
	{
	}

	private void add(Integer i)
	{
		i = Integer.valueOf(i.intValue() - 1);
	}

	private void reverse(String s)
	{
		s = "sey";
	}

	public static void main(String args[])
	{
		Integer i = Integer.valueOf(1);
		String s = "yes";
		Test test = new Test();
		test.add(i);
		test.reverse(s);
		System.out.println(String.format("i Value of:%d", new Object[] {
			i
		}));
		System.out.println(String.format("s Value of:%s", new Object[] {
			s
		}));
	}
}

We can clearly see that due to the java syntax sugar, Integer i = 1; Essentially Integer.valueOf(1). Then go deep into the Integer source code:

Familiar friends will know that Integer has a cache of - 128-127. Within this interval, it will directly get the cache from IntegerCache and return. Beyond this interval, it will return a new object.

Principle analysis

This time I will discuss from the of virtual machine stack and heap:
First, the JVM model is as follows:

(1) Display specific bytecode

implement javap -c Test.class The command decomposes the method code and displays the specific bytecode of each method
public class Test {
  public Test();
    Code:
       0: aload_0							// Load variables at local variable table [0] (usually this object)
       1: invokespecial #1 / / initialization method
       4: return							// Method end

  public static void main(java.lang.String[]);
    Code:
       0: iconst_1							// Pushes the constant 1 onto the operand stack
       1: invokestatic  #3 / / Boxing (Integer.valueOf()), returns an object and pushes it to the top of the stack
       4: astore_1							// The top element of the stack goes out of the stack and stores the reference in the local variable table [1]
       5: ldc           #5 / / String yes push the items in the constant pool onto the stack
       7: astore_2							// The top element of the stack goes out of the stack and stores the reference in the local variable table [2]
       8: new           #6 / / create a Test object (allocate memory on the heap and return a reference), and push the reference to the top of the stack
      11: dup								// The stack top element is out of the stack, and the stack top element is copied
      12: invokespecial #7 / / the top element of the stack is out of the stack, and the instantiation init() method is called
      15: astore_3							// The top element of the stack is out of the stack and will refer to the location where the local variable table [3] exists
      16: aload_3							// Load reference of local variable table [3] - > corresponding test
      17: aload_1							// Load reference of local variable table [1] - > corresponding i
      18: invokespecial #8 / / call the instantiation method test and add()
      21: aload_3							// Loading references to local variable table [3]
      22: aload_2							// Loading references to local variable table [2]
      23: invokespecial #9 / / call the instantiation method test and reverse()
      26: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      29: ldc           #11 / / value of string I:% d
      31: iconst_1
      32: anewarray     #12                 // class java/lang/Object
      35: dup
      36: iconst_0
      37: aload_1
      38: aastore
      39: invokestatic  #13                 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      42: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      45: getstatic     #10                 // Field java/lang/System.out:Ljava/io/PrintStream;
      48: ldc           #15 / / value of string:% s
      50: iconst_1
      51: anewarray     #12                 // class java/lang/Object
      54: dup
      55: iconst_0
      56: aload_2
      57: aastore
      58: invokestatic  #13                 // Method java/lang/String.format:(Ljava/lang/String;[Ljava/lang/Object;)Ljava/lang/String;
      61: invokevirtual #14                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
      64: return
}

(2) We know that the Java virtual machine is thread private. When each method is executed, the Java virtual machine will synchronously create a stack frame to store the local variable table, operand stack, dynamic link, method exit and other information. The process from the call of each method to the completion of execution corresponds to the process of a stack frame from stack entry to stack exit in the virtual machine stack, This time, we will discuss the stack frames of the two methods of the virtual machine stack: main(), add().

(3) As shown in the figure, main corresponds to a stack frame. The local variable table element i in the stack frame points to i in the heap and s points to s in the heap.

When line 18 of bytecode is executed in the main() method: invokespecial #8 / / call the instantiation method test and add() method
Because Java is passed by reference, the reference address of i in the local variable table is passed to the i parameter in the add() method of the instantiated object test. At the same time, the add() method is called, and the stack frame of the add() method is pressed into the Java Virtual machine stack. At the same time, the stack frame has its own local variable table i, which points to the memory i in the heap.

Because i is a local variable at this time, it only exists in the stack frame of add when executing the code

 i = i - 1;(Equivalent to execution  i = Integer.valueOf(i - 1) );

As shown in the figure, in the local variable table in the stack frame of the add() method, i memory points to i1.

To sum up, we can see that the memory address of the local variable table i in the stack frame of the original main() method has not changed, so it will not change when printing. Only the memory address in the heap pointed to by i in the local variable table in the add() stack frame is changed, which will not affect the i in the local variable table of the main() method.

summary

The transfer method in Java is reference transfer. If you want to modify the value of a variable in a method, you can only modify the value of the original variable pointing to the memory in the heap, not by changing the reference address of the object in the method.

public class Test {

    Integer x = 1;
    Integer y = 2;

    /**
     * Exchange variable
     */
    private void swap(Integer i1, Integer i2) {
        i1 = i1 ^ i2;
        i2 = i1 ^ i2;
        i1 = i1 ^ i2;
    }

    private void swap(Test test) {
        Integer x = test.x;
        Integer y = test.y;
        x = x ^ y;
        y = x ^ y;
        x = x ^ y;
        test.x = x;
        test.y = y;
    }
    public static void main(String[] args) {
        Integer i = 1;
        Integer j = 2;
        Test test = new Test();
        test.swap(i, j);

        System.out.println(i);
        System.out.println(j);

        test.swap(test);

        System.out.println(test.x);
        System.out.println(test.y);
    }
}

In this way, the values of variables can be successfully exchanged: the results are as follows

Tags: Java jvm

Posted on Sat, 02 Oct 2021 13:26:56 -0400 by bloo