【问题标题】:String in Java is object, so it should be reference? [duplicate]Java中的字符串是对象,所以它应该是引用? [复制]
【发布时间】:2014-04-20 17:21:21
【问题描述】:

我是Java初学者,最近遇到这样一个关于Java String概念的面试问题:

public class Test1 {

    public static void changeStr(String str){
        str="welcome";
    }

    public static void main(String[] args) {
        String str="1234";
        changeStr(str);
        System.out.println(str);
     }
}

我认为输出应该是“welcome”,但是,我在 Eclipse 中对其进行了测试,它显示“1234”,Java 字符串不是引用,因此 Java 字符串“str”引用更改为“welcome”在方法 changeStr 中?

请原谅我的初学者问题!

【问题讨论】:

    标签: java


    【解决方案1】:

    对象的引用传递给方法并赋值给参数,是一种局部变量。

    为参数分配一个不同的对象引用对持有原始对象引用的方法之外的变量没有任何作用。

    String 也是不可变的,因此无法更改其值(例如 setValue() 方法)。

    【讨论】:

    • 非常感谢,现在我知道我哪里错了:)。
    【解决方案2】:

    str = "welcome"; 行不会改变任何字符串的值——字符串永远不会改变它们的值。它的作用是使一个引用指向不同的字符串。但是它重新分配的引用是changeStr 的本地引用,而不是main 中声明的引用。

    【讨论】:

    • String strString str="1234" 不是同一个,它们是堆栈中的两个局部变量。这两个都引用字符串常量池中的字符串“1234”。但是在分配 str="welcome" 之后,String str 重新引用到“welcome”,而 String str="1234" 仍然引用“1234”。这里的关键,当你修饰一个字符串时,意味着你创建一个新的字符串而不是修饰符 iteft,因为 String 是不可变的。
    • @qmn1711 在我看来,您应该将其作为单独的答案发布,因为它与我所说的完全不同。
    • 但我在阅读您的评论后才理解这个问题。我认为它有联系:)
    【解决方案3】:

    String 是一个引用,但关键是 changeStr 中的 String str 与 main 中的 str 是不同的引用。再加上字符串在 Java 中是不可变的事实(这意味着当您更改字符串时,引用指向内存中的不同位置),这就解释了为什么 main 会打印 1234

    【讨论】:

      【解决方案4】:

      考虑以下示例:

      public static void main(final String[] args) throws Exception {
          final StringHolder holder = new StringHolder("old value");
          System.out.println(holder);
          reassignHolder(holder);
          System.out.println(holder);
          changeVal(holder);
          System.out.println(holder);
      }
      
      static void reassignHolder(StringHolder holder) {
          holder = new StringHolder("new value");
      }
      
      static void changeVal(StringHolder holder) {
          holder.setVal("new value");
      }
      
      static class StringHolder {
      
          private String val;
      
          public StringHolder(String val) {
              this.val = val;
          }
      
          public String getVal() {
              return val;
          }
      
          public void setVal(String val) {
              this.val = val;
          }
      
          @Override
          public String toString() {
              return "StringHolder{" + "val=" + val + '}';
          }
      
      }
      

      在 Java 中,引用是按值传递的,并且(几乎)一切都是对象引用。

      这里我们有一个可变对象,它包含一个String - 一个StringHolder

      当我们调用reassignHolder 时,我们实际上所做的是复制我们的对象引用并将其传递给方法。当该方法重新分配引用时,原始引用不会发生任何变化,因为我们正在传递一个副本。

      当我们调用reassignHolder 时,我们还传递了引用的副本,但是该方法使用此引用调用对象上的方法来更改其val 变量。这会产生影响。

      所以输出是:

      StringHolder{val=old value}
      StringHolder{val=old value}
      StringHolder{val=new value}
      

      由于String 是不可变的,所以只能执行第一个示例,而不能执行第二个示例。

      【讨论】:

        【解决方案5】:

        这里的逻辑是传递的str 值作为str 的引用副本传递。这意味着str 中的任何更改都不会反映在原始str 中。 这种情况类似于按值传递(但有引用!)

        但是,在您的代码中,如果您将代码更改为 str = new String("welcome");,它将更改原始的 str 字符串,使其引用已创建的新副本。

        希望这可以为您解决问题。

        【讨论】:

        • 我认为您的意思是“参考的副本”,而不是第一句话中的“参考副本”。
        • @DavidWallace:是的。感谢您指出。
        猜你喜欢
        • 2010-12-08
        • 2021-05-06
        • 1970-01-01
        • 2018-08-09
        • 2015-12-23
        • 2019-01-15
        • 2016-10-26
        • 1970-01-01
        • 2016-01-04
        相关资源
        最近更新 更多