【问题标题】:String Reference type in Java versus others in terms of objects [duplicate]Java中的字符串引用类型与对象方面的其他类型[重复]
【发布时间】:2021-03-24 00:49:42
【问题描述】:

所以我在看一个介绍性的 Java 教程,它说如果你声明一个引用类型,另一个等于那个对象,如果你改变第一个对象,第二个也会改变。例如:

Point p1 = new Point(1, 1);
Point p2 = p1;
p1.x = 5;
System.out.println(p2);

这会给我一个输出

java.awt.Point[x=5,y=1]

但是,我用字符串尝试了这个:

String s1 = "Hello, World!";
String s2 = s1;
s1 = "Goodbye, World!";
System.out.println(s2);

但我得到了

Hello, World!

作为输出。

为什么会发生这种情况,是否意味着字符串是一种特殊类型的引用类型,因为它们很常见?

【问题讨论】:

    标签: java string types reference


    【解决方案1】:

    String 是 java 中的一个“特殊”对象。它是一个不可变对象(固定且无法修改),并且是唯一可以在没有 new 关键字的情况下声明的对象。

    如果您使用 StringBuilderStringBuffer 这些是可变字符串,您的值将在更改时被修改。

    当您深入研究时,Java String 会带来许多令人困惑的理解。当您使用“==”时,具有相同值的 2 个不同字符串返回相同的内存地址引用。例如。

    String a1 = "abc"
    String a2 = "abc"
    a1 == a2 //returns true because a1 and a2 points to same reference (but not always!)
    a1 == new String("abc") //returns false
    /**Do use "equals", not == for string's value comparison**/
    

    如果你能把注意力集中在内存对象引用上:

    String s1 = "Hello, World!"; //let's say it's allocated to memory address 0x0012
    String s2 = s1; //s2 points to same memory address 0x0012
    s1 = "Goodbye, World!"; //s1 points to new memory address 0x1113
    System.out.println(s2) //printing value in still in memory address 0x0012
    

    相当于,s1指向新Object,s2指向旧Object。

    当您参考您的 Point 示例时

    Point p1 = new Point(1, 1);
    Point p2 = p1; //p2 is referring to p1's memory address
    p1.x = 5;  
    p1 = new Point(2,2); //Assign to new memory address, here is like the line for s1="Goodbye,world"
    System.out.println(p2.x); //You now still get 5, because it's still old object.
    

    因此,要修复可变字符串,您需要更改“Class”.“method”之类的内容,以保留正在修改的相同对象。因此类似于:

    StringBuilder sb1 = new StringBuilder("Hello World");
    StringBuilder sb2 = sb1;  //Points to same reference address.
    sb1.append("Goodbye World");
    System.out.println(sb2.toString()); //Now you get Hello WorldGoodbye World.
    sb1.setLength(0).append("Goodbye World"); //clear then set to new value.
    System.out.println(sb2.toString()); //Now you get Goodbye World.
    

    【讨论】:

    • 所以回到你的代码,s1 = "Goodbye, World!" 会自动创建一个新地址,而像 p1.x = 5 这样的东西仍然引用旧地址,对吧?
    • @dinosauce34 是
    • @BasilBourque 哦,错了。已更正,谢谢。
    【解决方案2】:

    我在 python 中处理了很多事情,情况也是如此。以一个列表为例,它存储了多个值。当您在 python 中完成等效的代码时,这将改变。字符串不会像您所说的那样改变。代码的问题是对象和类(如列表)会发生变化,因为它们没有存储在内存中。它们只是引用,而不是新对象。当您重新分配字符串时,分配工作正常,因为它只是一个值。

    【讨论】:

      【解决方案3】:

      Java 中的字符串是不可变对象。他们从不改变。当你做一个新的分配时,它只是创建一个新的字符串。旧的仍然由垃圾收集器收集。您的 Point 类不是不可变对象。

      【讨论】:

      • 所以只是澄清一下,当你更新点对象时,你会改变原来的对象,但如果你更新一个字符串,它会完全创建一个新的字符串,所以s2仍然是指原始的,没有改变一个对吗?
      • @dinosauce34:您更新字符串。将新对象重新分配给变量对旧对象或新对象没有任何作用。这对于 String 和任何其他对象都是一样的。
      • 区别在于p1.x = 5;改变了p1指向的对象。而s2 = s1 不会改变之前s2 指向的对象(或s1) 指向的对象。
      猜你喜欢
      • 2019-04-10
      • 2020-08-29
      • 2015-04-23
      • 2013-09-02
      • 1970-01-01
      • 2018-12-12
      • 2012-01-30
      • 2015-02-13
      • 1970-01-01
      相关资源
      最近更新 更多