Java到底是值传递还是引用传递

Java 采用值传递的机制。在 Java 中,当你将一个变量传递给一个方法时,实际上传递的是该变量的值,而不是变量的引用。这意味着在方法内部对参数的修改不会影响到原始调用方的变量。

需要注意的是,当传递引用类型(例如对象)时,传递的是引用的值,而不是引用本身。这就是为什么有时候人们可能会误认为 Java 使用引用传递。但实际上,引用的值仍然是一个拷贝,因此对参数的修改不会影响原始引用的指向。

下面通过一些例子来说明这一点:

1. **传递基本数据类型:**

   ```java
   public class PassByValueExample {
       public static void main(String[] args) {
           int x = 10;
           modifyValue(x);
           System.out.println(x);  // 输出:10
       }

       public static void modifyValue(int value) {
           value = 20;
       }
   }
   ```

   在这个例子中,`modifyValue` 方法修改了参数 `value` 的值,但这并不会影响到 `main` 方法中的变量 `x`。

2. **传递引用类型:**

   ```java
   public class PassByValueExample {
       public static void main(String[] args) {
           Person person = new Person("Alice");
           modifyReference(person);
           System.out.println(person.getName());  // 输出:Alice
       }

       public static void modifyReference(Person p) {
           p.setName("Bob");
       }
   }

   class Person {
       private String name;

       public Person(String name) {
           this.name = name;
       }

       public String getName() {
           return name;
       }

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

   在这个例子中,`modifyReference` 方法修改了传递进来的 `Person` 对象的状态,但这并不会改变 `main` 方法中的引用 `person` 所指向的对象。

因此,虽然在传递引用类型时传递的是引用的值,但仍然是值传递的特性,因为对于引用类型,传递的是引用的拷贝。

对于基本类型 num,赋值运算符会直接改变变量的值,原来的值被覆盖掉。

对于引用类型  字符串和对象,赋值运算符会改变引用中所保存的地址,原来的地址被覆盖掉。但是原来的对象不会被改变(重要)。

String类型在值传递和引用传递问题中比较特殊,为什么说特殊呢,因为对于一些常量字符串的创建,只要判断对象在堆中不存在,便会创建一个新的,如果是创建新对象,那么引用地址都会变。

在 Java 中,字符串的传递方式是值传递(pass by value)。当你将一个字符串传递给一个方法时,实际上传递的是字符串引用的拷贝,而不是字符串本身。这意味着在方法内部对字符串的修改不会影响原始调用方的字符串对象,因为字符串是不可变的。

下面通过一个简单的例子来说明字符串的值传递:

```java
public class StringPassByValueExample {
    public static void main(String[] args) {
        String str = "Hello";
        modifyString(str);
        System.out.println(str);  // 输出:Hello
    }

    public static void modifyString(String s) {
        s = s + " World";
    }
}
```

在这个例子中,`modifyString` 方法试图将传递进来的字符串 `s` 修改为 "Hello World",但在 `main` 方法中输出字符串 `str` 时,仍然是 "Hello"。这是因为对字符串进行修改实际上是创建了一个新的字符串对象,而原始字符串对象保持不变。

需要注意的是,虽然传递的是引用的拷贝,但对于字符串这种不可变对象,实际上并没有修改原始对象,而是创建了一个新的对象。如果你想在方法内部对字符串进行修改,并使得这些修改在原始引用中可见,可以考虑使用可变的字符串类,如 `StringBuilder` 或 `StringBuffer`。

总结一下,字符串在 Java 中的传递方式是值传递,即传递的是引用的拷贝,但由于字符串的不可变性,实际上并没有修改原始对象。

Java对象的传递,是通过复制的方式把引用关系传递了,如果我们没有改引用关系,而是找到引用的地址,把里面的内容改了,是会对调用方有影响的,因为大家指向的是同一个共享对象

我把我的钥匙复制给了我的朋友,但是我立马换了我家的锁。因为一new就会在堆上开辟新空间,地址就发生了改变,此时的user不再指向0x666了,理解为我换锁了,朋友当然进不了我家,砸不了电视了。所以此时在pass方法中修改name,不会对我家造成任何影响。

所以,值传递和引用传递的区别并不是传递的内容,而是实参到底有没有被复制一份给形参

在判断实参内容有没有受影响的时候,要看传的的是什么,如果你传递的是个地址,那么就看这个地址的变化会不会有影响,而不是看地址指向的对象的变化。

所以说,Java 中其实还是值传递,只不过对于对象参数,值的内容是对象的引用。

无论是值传递还是引用传递,其实都是一种求值策略 (Evaluation strategy)。在求值策略中,还有一种叫做按共享传递 (call by sharing)。其实 Java 中的参数传递严格意义上说应该是按共享传递。

按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。

在函数内部对参数进行操作时,需要先拷贝的地址寻找到具体的值,再进行操作。

如果该值在栈中,那么因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。

如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝,所以函数内对值的操作对外部变量是可见的。

简单点说,Java 中的传递,是值传递,而这个值,实际上是对象的引用。

  • 传递的值在栈中,直接拷贝一份值传递,改变的形参不会对实参造成影响
  • 传递的值在栈中存放的是地址(引用),先根据栈中的地址找到在堆上的值,然后把地址拷贝一份(拷贝的地址是一个值),此时形参和实参指向堆上同一个地址,形参的修改导致了实参的改变。

你可能感兴趣的:(java,开发语言)