【问题标题】:Java String immutable passed by reference/value通过引用/值传递的 Java 字符串不可变
【发布时间】:2013-02-16 23:57:26
【问题描述】:

您好,我正在为我的 scja 考试而学习,并且有一个关于通过 ref/value 传递的字符串以及它们如何不可变的问题。以下代码输出“abc abcfg”。

我想知道为什么会这样?我不明白方法 f 内部发生了什么。字符串是按值传递的,所以它肯定应该在方法内更改为“abcde”吗?因为如果 b+="fg" 附加到字符串,为什么它在方法内部不起作用?

谢谢!

public class Test {

    public static void main(String[] args){
        String a =new String("abc");
        String b = a;
        f(b);
        b+="fg"
        System.out.println(a + " " + b);
    }

    public static void f(String b){
        b+="de";
        b=null;
    }
}

【问题讨论】:

  • 要记住的关键是引用是按值传递的。 f 获取一个引用的副本,该引用最初是指向“fg”的指针。

标签: java


【解决方案1】:

void f(String b) 函数中的b+="de"; 行创建了一个全新的String 对象,它不会影响main 函数中的对象。

所以当我们说String不可变的 时意味着任何String 对象的更改将导致创建一个全新的String 对象

public class Test {
    public static void main(String[] args){
        String a =new String("abc");

        String b = a; // both a & b points to the same memory address

        f(b); // has no effect

        // b still has the value of "abc"
        b+="fg" // a new String object that points to different location than "a"

        System.out.println(a + " " + b); // should print "abc abcfg" 
    }

 public static void f(String b){
    b+="de";  // creates a new object that does not affect "b" variable in main
    b=null;
 }
}

【讨论】:

    【解决方案2】:

    在您的方法f() 中,您正在为参数b 分配一个新字符串,但是参数就像局部变量一样,因此为它们分配一些东西对方法之外的任何东西都没有影响。这就是你传入的字符串在方法调用后没有变化的原因。

    【讨论】:

    • 所以我不得不做 b = f(b) 并从方法 f 返回一个字符串?
    • 没错!即便如此,在您返回字符串之前,方法之外没有任何影响。
    • 它还指出,如果您要执行 b = f(b) 并使用当前编码返回一个字符串,那么您将得到输出“abc nullfg”,正如您所说的 b =空。
    • 我很确定这是非常不正确的。字符串作为值传递,值是指向字符串的指针。当你做任何事情时 b+="de";或 null,您会影响指针。 b+="de";等同于 b = new String;如果你做同样的事情,只是简单地将字符串扔到包装器中,并更改包装器中的数据,你会看到更改,因为你更改了包装器中的数据所具有的指针,而不是包装器本身。跨度>
    • @StarWind 当然。如果您 mutate 对象,那么是的,它是 same 对象被 changed 作为分配给调用代码中的变量的对象,因此更改是“见”法外也。 assignment 在调用代码中什么都不做。
    【解决方案3】:

    这行代码:

    b += "de";
    

    大致翻译为:

    b = b + "de";
    

    这会创建一个新字符串并将其存储在局部变量“b”中。无论如何,方法外的引用都不会因此而改变。在尝试了解这种方式如何/为什么会这样工作时,需要记住几件关键的事情。

    1. 在 Java 中,所有方法参数都是按值传递的。
    2. 方法有一个本地堆栈,其中存储了所有数据,包括方法参数。

    当您将新对象分配给传递给方法的变量时,您只是将本地堆栈中的地址替换为创建的新对象的地址。方法外的实际对象地址保持不变。

    【讨论】:

      【解决方案4】:

      当您将 String 传递给方法时,它会在方法中创建一个新的 String 对象。如果你在你的方法中加入 println 语句,像这样:

      public static void f(String b){
          b+="de";
          System.out.println(b);
          b=null;
      }
      

      您会看到输出“abcde”。

      然而,一旦你退出该方法,你就会回到你的原始对象,它没有被改变。因此,将 fg 附加到它只会产生一个新的字符串 (b),其中包含“abcfg”。

      【讨论】:

        【解决方案5】:

        当你说 b+="de" 时,你创建了一个新的 String 对象

        就像说 b = new String(b+"de");

        如果您真的想保留传入的值,请使用这样的 stringBuilder:

            StringBuilder a =new StringBuilder("abc");
                StringBuilder b = a;
                f(b);
                b.append("fg");
                System.out.println(a + " " + b);
            }
        
          public static void f(StringBuilder b){
                b.append("de");
                b=null;
            }
        

        现在您的输出将是“abcdefg”,因为 stringbuilder 对象 b 已作为对象本身的值传递给 f。我修改了值,但没有使用“new”来指向另一个对象。希望现在清楚。

        【讨论】:

          猜你喜欢
          • 2010-11-19
          • 2014-08-11
          • 2017-07-25
          • 2016-07-05
          • 1970-01-01
          • 2013-04-07
          • 2018-09-01
          • 2015-04-08
          • 1970-01-01
          相关资源
          最近更新 更多