java - 重新审视 Jon Skeet 在他的文章中发布的 Java 中的按值传递语义

标签 java pass-by-reference pass-by-value stringbuffer

我正在经历这个出色的article Jon Skeet 的 Java 引用语义,他指出

We assume the presence of a procedure named f that takes a formal parameter s. We call that function giving it an actual parameter g.

The calling code:

         f( g )

The function:

   procedure f( s )
   begin
     -- body of the procedure
   end;

All object instances in Java are allocated on the heap and can only be accessed through object references. So if I have the following:

       StringBuffer g = new StringBuffer( "Hello" );

The variable g does not contain the string "Hello", it contains a reference (or pointer) to an object instance that contains the string "Hello".

So if I then call f( g ), f is free to modify its formal parameter s to make it point to another StringBuffer or to set it to null. The function f could also modify the StringBuffer by appending " World" for instance. While this changes the value of that StringBuffer, the value of that StringBuffer is NOT the value of the actual parameter g.

我的理解可能是错误的。下面的程序确实更改了传递给该方法的 Stringbuffer

public class MutabilityStringBuffer {
    public static void main(String[] args){
        StringBuffer sb = new StringBuffer("hello");
        System.out.println("String before append: "+ sb.toString());
        addString(sb);
        System.out.println("Sting after append "+ sb.toString());

        String s = "hello";
        System.out.println("String before append: "+ s);
        addString(s);
        System.out.println("Sting after append "+ s);

    }
    public static void addString(StringBuffer word){
        word.append(" world!");
    }
    public static void addString(String word){
        word+=" world!";
    }

}

当然,乔恩·斯基特不会错。但我看到 Stringbuffer 可以通过将其传递给方法来更改,因为 stringbuffer 是可变的,这与 Skeet 发布的内容有点矛盾。请在这里澄清我的理解。

谢谢

最佳答案

查看评论

StringBuffer sb = new StringBuffer("hello"); // sb holds reference 
System.out.println("String before append: "+ sb.toString()); // you print the value 
addString(sb);  // you use the reference to append to the StringBuffer
System.out.println("Sting after append "+ sb.toString()); // you print the value

String s = "hello"; // s holds a refernece
System.out.println("String before append: "+ s); // you print its value
addString(s); // // the word variable would hold a new reference inside the method 
System.out.println("Sting after append "+ s); // you print its value

在这里

public static void addString(String word){
    word+=" world!";
}

传递给 word 的引用的原始值当您重新分配它时会发生变化

word+=" world!"; 

事情是这样的

String word = [copy of value of the argument's reference];
word = word.toString() /* toString() is unnecessary, but just to make the point */ + " world";

其中字符串连接的结果是一个新的字符串对象,因此是一个新的引用。

如下

public static void addString(StringBuffer word){
    word.append(" world!");
}

您访问 word 引用的对象,调用该对象上的方法,该方法在内部修改 char[] 。因此,您更改了对象的值,而不是引用的值。更改引用看起来像

public static void addString(StringBuffer word){
    word = new StringBuffer("Answer to the Ultimate Question of Life, the Universe, and Everything: ");
    word.append("42"); 
}

append在新的 StringBuffer 上执行对象,而不是您作为参数传递的对象,证明对象是按值传递的。

关于java - 重新审视 Jon Skeet 在他的文章中发布的 Java 中的按值传递语义,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18774339/

相关文章:

java - 带有 setter 注入(inject)的 Spring @Qualifier 奇怪行为

c++ - 复制 vector 并保留成员的内存地址

iphone - 为什么这里使用 "error:&error"(objective-c)

java - 使用 JNA 访问 .dll 时通过引用传递字符串

java - 疑惑,java在传递对象引用时是按值调用还是按引用调用?

android - 如何将值从一个 fragment 的回收者 View 项目传递到另一个 fragment

java - CheckBoxTableCell 不适用于 ObjectProperty<Boolean>

java - 创建唯一的对象实例变量

java - 如何使用 Intent 添加日历事件?

backbone.js - 一个实例中的 Backbone 模型更改数据会影响另一个实例