Stumped my colleague: Is the Java method call passed by value or by reference

Are the parameters in a Java method call passed by value or by reference? I believe that every student who is doing development has encountered this problem. Not only students who do Java, but students who develop with C# and Python must have encountered this problem, and it is very likely that it has been encountered more than once.

So, is it passed by value or by reference in Java? The answer is by value. There is no concept of pass by reference in Java.

Data types and memory allocation

There are two types of data types that can be summarized in Java, one is the basic type, and the other is the reference type.

basic type

Byte, short, int, long, float, double, char, boolean are the eight basic types in Java. The basic type of memory allocation is done on the stack, which is the virtual machine stack of the JVM. In other words, when you use the following statement:

int i = 89;

4 bytes of space will be allocated on the virtual machine stack for storage.

Reference type

Reference types include classes, interfaces, arrays, and null. The various custom entity classes that we are usually familiar with are in this category.

When we define an object and use the new keyword to instantiate the object.

User user = new User();

Will go through the following three steps:

1. Declare a reference variable user and allocate space on the virtual machine stack;

2. Use the new keyword to create an object instance, and allocate space on the heap to store the attribute information in the object;

3. Link the objects on the heap to the user variable, so what is stored on the stack is actually the address information of the stored objects on the heap;

The same is true for array objects. Only an address is stored on the stack, pointing to the array space actually allocated on the heap, and the actual value is stored on the heap.

In order to clearly show the space allocation, I have drawn a sample diagram of the type space allocation.
Insert picture description here
Basic types without disputes
When we pass 8 basic types as method parameters, there is no dispute. What is passed (that is, actual parameters), and what is received in the method (that is, formal parameters). What is passed is 1 and what is received is 1, what is passed is true, and what is received is true.

Look at the following example, pass the variable oldIntValue to the changeIntValue method, modify the parameter value in the method, and the final output result is still 1.

public static void main( String[] args ) throws Exception{
    
    
	int oldIntValue = 1;
	System.out.println( oldIntValue );
	passByValueOrRef.changeIntValue( oldIntValue );
	System.out.println( oldIntValue );
}

public static void changeIntValue( int oldValue ){
    
    
	int newValue = 100;
	oldValue = newValue;
}

Changing the parameter value does not change the value of the original variable. That's right, Java passes by value.

Arrays and classes
Arrays

Some students said that was wrong. Look at the code below, it is not the case.

public static void main( String[] args ) throws Exception{
    
    
	int[] oldArray = new int[] {
    
     1, 2 };
	System.out.println( oldArray[0] );
	changeArrayValue( oldArray );
	System.out.println( oldArray[0] );
}

public static void changeArrayValue( int[] newArray ){
    
    
	newArray[0] = 100;
}

The output of this code is

1
100

Explain that when the changeArrayValue method is called, after the first item in the passed array parameter is modified, the content of the original variable changes, so how is this value transfer?

Don't worry, take a look at the following picture, which shows an example of the memory allocation of an array in the JVM.
Insert picture description here
In fact, it can be understood that the parameter received by the changeArrayValue method is a copy of the original variable oldArray, but the array reference only points to the first address of the array space in the heap. Therefore, when the changeArrayValue method is called, oldArray and newArray are formed The reference addresses of the two variables in the stack all point to the same array address. So modifying each element of the parameter is equivalent to modifying the element of the original variable.

class

Generally, there are many cases where we use class instances as parameters in the development process, and various objects we abstract are often passed between methods. For example, we define a user entity class.

public class User {
    
    

    private String name;

    private int age;

    public User(String name, int age) {
    
    
        this.name = name;
        this.age = age;
    }

    public String getName() {
    
    
        return name;
    }

    public void setName(String name) {
    
    
        this.name = name;
    }

    public int getAge() {
    
    
        return age;
    }

    public void setAge(int age) {
    
    
        this.age = age;
    }

    @Override
    public String toString() {
    
    
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

For example, we have a primitive entity User class object, and pass this entity object to a method. This method may have some logic processing. For example, when we get the name attribute of the user and find that the name is empty, we give the name attribute Give a random name, such as "User 398988". This should be a very common scenario.

We usually use it like this, passing the user instance as a parameter, and returning it after the processing is complete.

public static void main( String[] args ) throws Exception{
    
    
	User oldUser = new User( "原始姓名", 8 );
	System.out.println( oldUser.toString() );
	oldUser = changeUserValue( oldUser );
	System.out.println( oldUser.toString() );
}

public static User changeUserValue( User newUser ){
    
    
	newUser.setName( "新名字" );
	newUser.setAge( 18 );
  return newUser;
}

However, some students said that I found that even if it does not return after the modification is completed, the properties of the original variable oldUser are also changed, such as the following:

public static void main( String[] args ) throws Exception{
    
    
	User oldUser = new User( "原始姓名", 8 );
	System.out.println( oldUser.toString() );
	changeUserValue( oldUser );
	System.out.println( oldUser.toString() );
}

public static void changeUserValue( User newUser ){
    
    
	newUser.setName( "新名字" );
	newUser.setAge( 18 );
}

The results returned are as follows

User{
    
    name='原始姓名', age=8}
User{
    
    name='新名字', age=18}

Isn't this just passing by reference? Changing the attribute of the parameter changes the attribute of the original variable. Still look at a picture.
Insert picture description here
Actually, it is still not a reference pass. When we learn C++, we often use reference pass, which is pointers. And what is passed here is actually a copy, and only the address pointing to the heap space object entity is stored in the copy. We modify the properties of the parameter newUser indirectly to modify the properties of the original variable.

Some students said that drawing a picture and saying this is the case? Do you say that a copy is a copy? I prefer to say that it is a reference to the original variable, which makes sense.

It really makes sense, if it is really passed by reference, it is indeed the effect. Then we have a counterexample.

public static void main( String[] args ) throws Exception{
    
    
	User oldUser = new User( "原始姓名", 8 );
	System.out.println( oldUser.toString() );
	wantChangeUser( oldUser );
	System.out.println( oldUser.toString() );
}

public static void wantChangeUser( User newUser ){
    
    
	newUser = new User( "新姓名", 18 );
}

Assuming it is passed by reference, then the oldUser in the newUser and the main method is the same reference object. Then I renewed a User entity in the wantChangeUser method and assigned it to newUser. According to the argument of passing by reference, I assigned the value to the parameter. It is assigned to the original variable, then when the assignment operation is completed, the original variable oldUser should be name = "new name" and age = 18.

Then, we run to see the output:

User{
    
    name='原始姓名', age=8}
User{
    
    name='原始姓名', age=8}

The result is still the value before the modification. We modified the newUser without affecting the original variable, which is obviously not passed by reference.

in conclusion

Parameter passing in Java is passing by value, and there is no concept of passing by reference in Java. We usually talk about passing by reference, usually from the C language and C like, because they have the concept of pointers.

And we also know that in C and C++ programmers need to manage memory by themselves, and the use of pointers often leads to problems such as memory leaks. Java uses garbage collection strategy management to free the programmers. Memory, one of the very important points is to avoid the use of pointers, so there is no so-called pointer passing in the Java world.

Learn Java programming with zero foundation, you can join my ten-year Java learning field .

Guess you like

Origin blog.csdn.net/weixin_49794051/article/details/112468084