Is Java parameter passing by value or by reference?

Posted by dshevnock on Thu, 06 Jan 2022 08:18:18 +0100

preface

First of all, it is clear that method parameters in Java are passed by value. For basic types (int a, long b), values are passed when parameters are passed. For example, if int a = 5, 5 is passed. If it is a reference type, pass the address value pointing to the memory address of the specific object, such as system out. Println (New object()) printed out Java lang. Object@7716f4 7716f4 after the @ symbol in is the hexadecimal memory address, system out. Println actually calls the toString method of the object by default,

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

You can see that 7716f4 is output by hashCode(). If an object rewrites the hashCode method, the output may not be the initial memory address of the object. Therefore, if you want to accurately obtain the initial address of the object, it is recommended to call system identityHashCode().

It is worth mentioning that it is generally meaningless to obtain the memory address of an object in Java, because it may be changed by the JVM with actions such as garbage collection during program operation. However, in the following, we can see various situations of parameter passing according to whether the referenced object addresses are the same.

Examples

Basic types are passed as parameters

public class ValuePass {

    public static void main(String[] args) {

        //Example of value transfer
        int num = 10;
        System.out.println("Change previous value:" + num);
        modify(num);
        System.out.println("Changed value:" + num);
    }

    private static void modify(int num2) {
        num2 = 11;
    }
}

The output result is

Change previous value:10
 Changed value:10

This example shows that when the basic data type is passed as a parameter, a copy of the value is passed. No matter how the copy is changed, the original value will not change.

Object is passed as a parameter

Objects can be divided into ordinary objects, collection types and array types. Let's take a look at the effect in turn

Common object

public class ReferenceBasicPass {

    static class TreeNode {
        int val;
        TreeNode left;
        TreeNode right;
        public TreeNode(int x) { val = x; }

        public void setVal(int val) {
            this.val = val;
        }

        public int getVal() {
            return val;
        }
    }

    public static void main(String[] args) {

        //Common object
        TreeNode node = new TreeNode(10);
        System.out.println("Argument node The memory address pointed to is:" + node.hashCode());
        System.out.println("Change previous value:" + node.getVal());
        modify(node);
        System.out.println("Changed value:" + node.getVal());
    }

    private static void modify(TreeNode node) {
        System.out.println("Formal parameter node The memory address pointed to is:" + node.hashCode());
        //It refers to the same block of address and operates on the same block of heap memory
        node.setVal(11);
    }

}

Output results

Argument node The memory address pointed to is 366712642
 Change previous value:10
 Formal parameter node The memory address pointed to is 366712642
 Changed value:11

This shows that when the reference object parameter is passed, the address pointing to the real object is passed, and when the formal parameter node in the function gets the same address, it passes through node SETVAL (11) will find the real object through the address for operation.

Collection object

Since ArrayList overrides the hashcode() method, system. XML is used here Identityhashcode gets the address value.

public class ReferencePass {

    public static void main(String[] args) {

        //Collection object
        List<TreeNode> nodes = new ArrayList<>();
        nodes.add(new TreeNode(1));
        nodes.add(new TreeNode(2));
        System.out.println("Modify previous arguments node The memory address pointed to is:" + System.identityHashCode(nodes));
        System.out.println("Modify previous arguments node The contents of the object stored at the address are:" + JsonUtils.toJson(nodes));
        modify(nodes);
        System.out.println("Modified argument node The memory address pointed to is:" + System.identityHashCode(nodes));
        System.out.println("Modified argument node The contents of the object stored at the address are:" + JsonUtils.toJson(nodes));

        System.out.println("\n------------------------------------------------\n");
        modify2(nodes);
        System.out.println("Modify the argument again node The memory address pointed to is:" + System.identityHashCode(nodes));
        System.out.println("Modify the argument again nodes The contents of the object stored at the address are:" + JsonUtils.toJson(nodes));
    }

    private static void modify(List<TreeNode> nodes) {
        //It refers to the same block of address and operates on the same block of heap memory
        nodes.add(new TreeNode(3));
    }

    private static void modify2(List<TreeNode> nodes) {
        System.out.println("Formal parameter nodes Memory address to:" + nodes.hashCode());
        //The formal parameter nodes points to the new memory address, which is operated on, but does not affect the real object of the memory address pointed to by the argument
        nodes = new ArrayList<>();
        nodes.add(new TreeNode(5));
        System.out.println("Formal parameter nodes New memory address to:" + nodes.hashCode());
        System.out.println("Formal parameter nodes The contents of the object stored at the new address are:" + JsonUtils.toJson(nodes));
    }
}

The output result is

Modify previous arguments node The memory address pointed to is 366712642
 Modify previous arguments node The contents of the object stored at the address are:[{"val":1},{"val":2}]
Modified argument node The memory address pointed to is 366712642
 Modified argument node The contents of the object stored at the address are:[{"val":1},{"val":2},{"val":3}]

------------------------------------------------

Formal parameter nodes Memory address pointed to: 1110478811
 Formal parameter nodes New memory address pointed to: 1458540949
 Formal parameter nodes The contents of the object stored at the new address are:[{"val":5}]
Modify the argument again node The memory address pointed to is 366712642
 Modify the argument again nodes The contents of the object stored at the address are:[{"val":1},{"val":2},{"val":3}]

For the collection, the reference address is also passed. After the reference address is copied through the formal parameter in the function, the real object is operated. As a result, the actual parameter has been modified when accessing the real object. If the parameter points to a new memory address, the modification will not affect the value of the original object.

Note: JsonUtils is implemented by Jackson.

array

Ordinary arrays, like collections, are reference types

public class ReferenceArrayPass {

    public static void main(String[] args) {

        //An ordinary array, like a collection, is a reference type, and an array is essentially a reference type
        int[] ints = new int[3];
        ints[0] = 1;
        ints[1] = 2;
        System.out.println("Argument ints The memory address pointed to is:" + System.identityHashCode(ints));
        System.out.println("Before modification ints Value with index 2" + ints[2]);
        modify(ints);
        System.out.println("After modification ints Value with index 2" + ints[2]);
        //The class of an ordinary array is [I, and I represents int type
        System.out.println(ints.getClass());
    }

    private static void modify(int[] ints) {
        //It refers to the same block of address and operates on the same block of heap memory
        System.out.println("Formal parameter ints The memory address pointed to is:" + System.identityHashCode(ints));
        ints[2] = 3;
    }

}

output

Argument ints The memory address pointed to is 366712642
 Before modification ints Value with index 2: 0
 Formal parameter ints The memory address pointed to is 366712642
 After modification ints Value with index 2: 3

The same is true for arrays and collections.

Packing type of basic type

It should be noted that for the basic type of packaging type, the parameter transfer also belongs to address value transfer;

public class ValuePass {

    public static void main(String[] args) {

        //Example of value transfer
        int num = 10;
        System.out.println("before modify result:" + num);
        modify(num);
        System.out.println("after modify result:" + num);

        Integer integer = 20;
        System.out.println("before modify result:" + integer);
        modify(num);
        System.out.println("after modify result:" + integer);
    }


    private static void modify(int num2) {
        num2 = 11;
    }

    private static void modify(Integer integer) {
        integer = 21;
    }
}

 

The output result is

before modify result:10
after modify result:10
before modify result:20
after modify result:20

And because jdk1 5. For the above automatic boxing feature, Integer i = 20 is equivalent to executing Integer I = Integer Valueof (20), the valueOf() method will get an Integer object from the constant pool and return it according to the passed value if it is between - 128-127. If it is not within the range, it will return new Integer(20).

That is, the address of integer will change with the change of value, which is actually the assignment of reference type, pointing to the new memory address. For example, the example of integer = 21 above is equivalent to integer = integer Valueof (21), whether or not it has been created before 21, integer points to the new memory address, but does not affect the argument. The external is still 20

 

Topics: Java Back-end Distribution architecture