考虑下面的例子。

String str = new String();

str  = "Hello";
System.out.println(str);  //Prints Hello

str = "Help!";
System.out.println(str);  //Prints Help!

在Java中,String对象是不可变的。那么为什么对象str可以被赋值为"Help!"呢?这难道不是与Java中字符串的不变性相矛盾吗?有人能给我解释一下不变性的确切概念吗?

编辑:

好的。我现在明白了,但还有一个问题。下面的代码呢:

String str = "Mississippi"; 
System.out.println(str); // prints Mississippi 

str = str.replace("i", "!"); 
System.out.println(str); // prints M!ss!ss!pp! 

这是否意味着将再次创建两个对象(“Mississippi”和“M!ss!ss!pp!”),并且在replace()方法之后引用str指向不同的对象?


当前回答

    public final class String_Test {

    String name;
    List<String> list=new ArrayList<String>();

    public static void main(String[] args) {

        String_Test obj=new String_Test();
        obj.list.add("item");//List will point to a memory unit- i.e will have one Hashcode value #1234

        List<String> list2=obj.list; //lis1 also will point to same #1234

        obj.list.add("new item");//Hashcode of list is not altered- List is mutable, so reference remains same, only value in that memory location changes

        String name2=obj.name="Myname"; // name2 and name will point to same instance of string -Hashcode #5678
        obj.name = "second name";// String is Immutable- New String HAI is created and name will point to this new instance- bcoz of this Hashcode changes here #0089

        System.out.println(obj.list.hashCode());
        System.out.println(list2.hashCode());
        System.out.println(list3.hashCode());

        System.out.println("===========");
        System.out.println(obj.name.hashCode());
        System.out.println(name2.hashCode());
    }
}

会产生这样的东西吗

1419358369 1419358369

103056 65078777

不可变对象的目的是它的值一旦被赋值就不应该被改变。 它将返回新对象,每次你试图改变它基于实现。 注意:可以使用Stringbuffer而不是string来避免这种情况。

对于你的最后一个问题::u将有一个引用,在字符串池中有2个字符串。 除了参考将指向m!ss!ss!pp!

其他回答

这里的不可变性意味着实例可以指向其他引用,但字符串的原始内容不会在原始引用处被修改。 让我用你举的第一个例子来解释。 第一个str指向“Hello”,这是可以的。 第二次它指向“救命!”。 这里str开始指向“Help!”,“Hello”字符串的引用丢失了,我们无法恢复。

事实上,当str试图修改现有内容时,将生成另一个新字符串,str将开始指向该引用。 所以我们看到,在原始引用处的字符串没有被修改,但在它的引用处是安全的,对象的实例开始指向不同的引用,所以不变性是保留的。

str引用的对象可以更改,但实际的String对象本身不能更改。

包含字符串“Hello”和“Help!”的String对象不能改变它们的值,因此它们是不可变的。

String对象的不可变性并不意味着指向该对象的引用不能改变。

防止str引用更改的一种方法是将其声明为final:

final String STR = "Hello";

现在,尝试将另一个String赋值给STR将导致编译错误。

Object字符串-方法本身是“不可变的”。 此操作不会产生任何更改:“字母”。替换(“bbb”、“aaa”);“

但是分配数据会导致Strings内容的改变:

    letters = "aaa";
    letters=null;
    System.out.println(letters);
    System.out.println(oB.hashCode());
    System.out.println(letters);
    letters = "bbbaaa";
    System.out.println(oB.hashCode());
    System.out.println(letters);

// string Object的hashcode不变。

关于你问题的替换部分,试试这个:

String str = "Mississippi"; 
System.out.println(str); //Prints Mississippi 

String other = str.replace("i", "!"); 
System.out.println(str); //still prints Mississippi 
System.out.println(other);  // prints M!ss!ss!pp!

在Java中,对象通常是通过引用访问的。在你的代码段中,str是一个引用,它首先被赋值给“Hello”(一个自动创建的对象或从常量池中获取的对象),然后你将另一个对象“Help!”赋值给同一个引用。需要注意的一点是,引用是相同的,但对象是不同的。代码中还有一件事,你访问了三个对象,

当你调用new String()。 当你分配"hello"的时候。 当你说“救命!”

调用new String()会创建一个新对象,即使它存在于字符串池中,所以通常不应该使用它。要将new string()创建的字符串放入字符串池,可以尝试intern()方法。

我希望这能有所帮助。