background

Is Java passed by value or by reference? The question has long been controversial. After looking up a lot of data, the results show that most of the opinions tend to be that Java is value delivered, some of them focus on whether the topic itself is reasonable, and a small number of people may be more confused after reading a lot of relevant data, and also raise doubts according to their own understanding.

As the saying goes, there are a thousand Hamlets in a thousand people’s eyes, so there is no need to get too tangled up. I will just sort out and analyze the most common point in this article: There is only value passing in Java. Sorting out this article is mainly to make their own memory more profound, of course, if published to see a little help is also very good.

define

Let’s start with a simple example 1:

// 例1
public class Main {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        change(a, b);
        System.out.println(a);
        System.out.println(b);
    }
    
    public static void change (int c, int d){
        c = 50;
        d = 60; }}Copy the code

Output result:

Before delivery: 10, 20 After delivery: 10, 20

In other words, the original values of a and B are not changed after they are passed to the change method, which is called value passing. If the original values are changed after the change method, it is referred to as passing.

  • Pass by value: When a function is called, a copy of the actual parameter is passed to the function so that the actual parameter is not affected if it is modified.
  • Pass by reference: When a function is called, the address of the actual parameter is directly passed to the function. Then, the modification of the parameter in the function will affect the actual parameter.

Java Core Technology Volume 1 says:

Call-by-value (value passing) means that a method accepts a value provided by the caller. Call-by-reference (pass-by-reference) means that the method accepts the address of the variable provided by the caller. Method can change the value of a variable passed by reference, but not by value.

Analysis of the

Example 1 in the definition shows that Java is the result of value passing, but one might argue with example 2:

// 例2
public class Main {

    public static void main(String[] args) {
        User user = new User();
        user.setName("Xiao pang");
        user.setAge(23);
        System.out.println("Before conversion:" + user.toString());
        change(user);
        System.out.println("After conversion:" + user.toString());
    }

    public static void change (User user){
        user.setName("Black");
        user.setAge(25); }}Copy the code

Running results:

User{name=’ age ‘, age=’25’}

The same change method, the same execution process, but the value of the argument is changed, according to the definition of the above is not a reference pass. One might conclude that Java methods pass primitive data types by value and reference data types by reference.

This conclusion is still wrong, as shown in example 3 below:

// 例3
public class Main {

    public static void main(String[] args) {
        String name = "Xiao pang";
        System.out.println("Before conversion:" + name);
        change(name);
        System.out.println("After conversion:" + name);
    }

    public static void change (String name){
        name = "Black"; }}Copy the code

Running results:

Before the switch: Fatty After the switch: Fatty

What’s going on here? String is also a reference data type, so the original value is not changed after being passed.


Heap memory, stack memory

The three examples above may be a source of confusion. To understand why the above three examples work, we need to introduce some knowledge about heap and stack memory in Java:

  • Heap memory is used to hold objects and arrays created by new.
  • Once an array or object is created in the heap, you can also define a special variable on the stack whose value is equal to the initial address of the array or object in the heap. The variable in the stack becomes a reference variable to the array or object

Compare the characteristics of the two:

The storage area Store content advantages disadvantages recycling
The stack References to variables and objects of primitive types Access is faster than the heap, second only to registers, and stack data can be shared The size and lifetime of the data in the stack must be fixed and inflexible Java automatically releases a variable when it is out of scope
The heap Objects and arrays created by instructions such as new Memory size can be allocated dynamically, and the lifetime does not have to be told to the compiler To allocate memory dynamically at run time, access is slow Data that is no longer used is reclaimed by the Automatic garbage collector of the Java virtual machine

A reference variable is essentially a name given to an array or object, and you can then use this name on the stack (reference variable) to access the array or object in the heap.

Now that we know about heap and stack memory, we can explain the above example:

The User object created in example 2, User User = new User(), actually goes through these steps:

 User user;    // create space in stack memory for the reference variable user, user=null
 user = new User();
 // 1. new User() creates space in the heap for an object of class User, which has no name
 // 2. User() then calls the constructor of the User class
 // 3. Assign the heap address of the User object to the reference variable User in the stack
Copy the code

This should give you an idea of how reference types are passed,

public class Main {

    public static void main(String[] args) {
        User user = new User();
        user.setName("Xiao pang");
        user.setAge(23);
        System.out.println("Before conversion:" + user.toString());
        change(user); // The reference address of the object in stack memory is passed
        System.out.println("After conversion:" + user.toString());
    }

    public static void change (User user){
        user.setName("Black");
        user.setAge(25); }}Copy the code

change(user); The value passed is actually a reference to the object in stack memory, and the method gets a copy of the object reference. Both the original object reference and the copy refer to the same object. The reference itself is also a value, and then changing the specific property value of the object to which the reference refers is equivalent to manipulating the original object. So the original value of example 2 will be changed.

Look at example 4 below:

Public class Main {public static void Main (String[] args) {User User = new User(); User. Elegantly-named setName (" xiao pang "); user.setAge(23); System.out.println(" before conversion: "+ user.toString()); change(user); System.out.println(" after conversion: "+ user.toString()); } public static void change(User user) { user = new User(); User. Elegantly-named setName (" black "); user.setAge(25); }}Copy the code

Running results:

User{name=’ age ‘, User{name=’ age ‘, age=’23’}

Add a line of code user = new user () to the change method.

user = new User(); If a reference variable refers to a new object, the user is no longer a reference to the original object in the main method. If a reference variable refers to a new object, the user is no longer a reference to the original object in the main method.

Also, this example illustrates example 3 above,

// 例3
public class Main {

    public static void main(String[] args) {
        String name = "Xiao pang";
        System.out.println("Before conversion:" + name);
        change(name);
        System.out.println("After conversion:" + name);
    }

    public static void change (String name){
        name = "Black";  // this is equivalent to name = new String(" black ");}}Copy the code

Name = new String(” black “); Strings are final and cannot be changed. The first two are just written differently.

Add example 5:

Public class Main {public static void Main (String[] args) {public static void Main (String[] args) {public static void Main (String[] args) {public static void Main (String[] args) {public static void Main (String[] args) {public static void Main (String[] args); System.out.println(" before conversion: "+ s.tostring ()); change(s); System.out.println(" after conversion: "+ s.tostring ()); } public static void change(StringBuffer s) { s.append(23); }}Copy the code

Running results:

Before conversion: Small fat after conversion: small fat 23

The s in change and the s in main still refer to the same object. Stringbuffers are not final and can be changed. The append method also changes the original string.

conclusion

What you can and can’t do with method parameters in Java:

* Methods cannot modify the parameters of basic data types (that is, numeric or Boolean). * Methods can change the state of object parameters. The * method cannot make an object parameter reference to a new object.Copy the code

To quote from Ideas for Java Programming:

If you assign an object to another object, you are copying a reference from one place to another.

If there are any mistakes, please correct them.