This is the 12th day of my participation in the Last Text Challenge of November 2021. When I went to work today, my colleague found an interesting problem. He passes a String argument to the method and changes the value of the reference within the method. He then uses the value outside the method and finds that the String is the same value, unchanged.

As we all know, Java is divided into value passing and reference passing. The value is passed when the parameter is a primitive type, and the reference is passed when the parameter is a wrapper type. Such as:

1. Basic type parameters

public class Test {

    public static void main(String[] args) {

        int num = 0 ;

        changeNum(num);

        System.out.println("num="+num);

    }

    private static void changeNum(int num) {

        num = 1; }}Copy the code

The printed result is num=0.

2. Encapsulating type parameters (reference types)

public class Test {

    public static void main(String[] args) {

        Product p = new Product();

        p.setProName("before");

        p.setNum(0);

        changeProduct(p);

        System.out.println("p.proName="+p.getProName());

        System.out.println("p.num="+p.getNum());

    }


    private static void changeProduct(Product p) {

        p.setProName("after");
        p.setNum(1); }}class Product {

    private int num;

    private String proName;

    public int getNum(a) {
        return num;
    }
    public void setNum(int num) {
        this.num = num;
    }
    public String getProName(a) {
        return proName;
    }

    public void setProName(String proName) {
        this.proName = proName; }}Copy the code

The result of the run is: p.proname =after and p.num=1.

3.String (String is a special reference type, so when passing a reference, the JVM does something special and does not change the original value)

The two examples above are obvious value passing and reference passing. But what if the argument is String? Let’s look at a concrete example:

public class Test {
    public static void main(String[] args) {
        String str = "ab";
        changeString(str);
        System.out.println("str="+str);
    }
    private static void changeString(String str) {
        str = "cd"; }}Copy the code

Can you guess what the result is? Following the previous example, String should be a wrapper type, it should be reference-passed, it should be changeable, and the result of the run should be “CD”. Let’s actually run it and see,

STR is equal to ab. How do we explain that? Is String a primitive type? It doesn’t make any sense.

This starts with the underlying mechanism of Java, where the memory model is divided into heap and stack.

  1. Variables of primitive types are placed on the stack;
  2. In wrapper types (reference types), objects are placed in the heap and references to objects are placed on the stack.

When Java passes parameters to a method, it makes a copy of the variable and passes it into the method body for execution. This sentence is difficult to understand and is the essence of the explanation of the problem. Let’s first explain the basic type of delivery in terms of this statement

Basic type of delivery:

  1. The vm assigns num a memory address and stores a value of 0.
  2. The virtual machine duplicates a num. We call it num ‘. The memory address of num and num is different, but the value of num is 0.
  3. The vm calls the num ‘method, which changes the value of num’ to 1.
  4. The value of num is not changed, so it is 0.

Passing of encapsulating types (reference types) :

  1. The virtual machine creates a Product memory space in the heap, which contains proName and NUM.
  2. The virtual machine assigns P a memory address on the stack that holds the memory address of Product in 1.
  3. The virtual machine copies a p, we call it p ‘. The memory address of p and p ‘is different, but they store the same value, which is the memory address of Product in 1.
  4. Passing p ‘into the method changes proName and num in 1.
  5. At the end of the method, the value of the variable in p is printed outside the method. Since both P and P ‘store the address of Product in 1, but the value of Product in 1 has changed, the value of P printed outside the method is after the execution of the method. The effect we see is that the value of the wrapper type is changed.

The steps in the String passing process:

  1. The VM creates a block of memory in the heap and stores the value ab.
  2. The virtual machine assigns STR a memory on the stack that holds the address of 1.
  3. The virtual machine makes a copy of STR, which we call STR ‘. STR and STR ‘have different memory, but both stores addresses with values of 1.
  4. Pass STR ‘into the method body
  5. The method body creates a block of memory in the heap and stores the value “CD”
  6. The method body changes the value of STR ‘to the memory address of 5 == (this step is key) ==
  7. The method ends and prints STR. Since STR holds the address of 1, it prints “ab”.

So we understand the whole process of Java passing parameters to methods. When Java passes parameters to a method, it makes a copy of the variable and passes it to the method body to execute. = =