Java中字符串的不變性



Answers

str引用可以改變的對象,但實際的String對象本身不能。

包含字符串"Hello""Help!"String對象 不能改變他們的價值觀,因此他們是不可改變的。

String對象的不變性並不意味著指向該對象的引用不能改變。

阻止str引用發生變化的一種方法是將其聲明為final

final String STR = "Hello";

現在,試圖將另一個String分配給STR將導致編譯錯誤。

Question

考慮下面的例子。

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!”),並且引用strreplace()方法之後指向另一個對象?




因為字符串是不可變的,所以如果你不會將函數的返回值賦值給string.so,那麼就不會發生變化,在你的問題中賦值swap函數返回值給s。

s = swap(s,n1,n2);那麼字符串s的值將會改變。

當我編寫程序來獲取一些排列字符串時,我也得到了不變的值(儘管它沒有給出所有的排列,但這是例如回答你的問題)

這是一個例子。

> import java.io.*;  public class MyString { public static void
> main(String []args)throws IOException {  BufferedReader br=new
> BufferedReader(new InputStreamReader(System.in));  String
> s=br.readLine().trim(); int n=0;int k=0;  while(n!=s.length()) {
> while(k<n){  swap(s,k,n); System.out.println(s); swap(s,k,n); k++; }
> n++; } }  public static void swap(String s,int n1,int n2) { char temp;
> temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s);
> sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString();
> } }

但我沒有從上面的代碼中獲取字符串的置換值。因此,我將交換函數的返回值賦值給字符串,並獲得了字符串的更改值。 分配返回的值後,我得到了字符串的置換值。

/import java.util.*; import java.io.*; public class MyString { public static void main(String []args)throws IOException{
BufferedReader br=new BufferedReader(new InputStreamReader(System.in)); 
String s=br.readLine().trim(); int n=0;int k=0; 
while(n!=s.length()){ while(k<n){ s=swap(s,k,n); 
System.out.println(s); s=swap(s,k,n); k++; } n++; } } 
public static String swap(String s,int n1,int n2){
char temp; temp=s.charAt(n1); StringBuilder sb=new StringBuilder(s); sb.setCharAt(n1,s.charAt(n2)); sb.setCharAt(n2,temp); s=sb.toString(); return s; } }



不可變性意味著實例化對象的值不能改變,你永遠不能把“Hello”變成“Help!”。

變量str是一個對象的引用,當你為str指定一個新的值時,你並沒有改變它引用的對象的值,那麼你引用了一個不同的對象。




字符串是不可變的,意味著你不能改變對象本身,但你可以改變對象的引用。 當你調用一個=“ty”時,你實際上是將a的引用改為一個由字符串文字“ty”創建的新對象。 改變一個對象意味著使用它的方法來改變它的一個字段(或者這些字段是公開的而不是最終的,以便它們可以從外部更新而不用通過方法訪問它們),例如:

Foo x = new Foo("the field");
x.setField("a new field");
System.out.println(x.getField()); // prints "a new field"

雖然在一個不可變的類中(聲明為final,以防止通過繼承進行修改)(其方法不能修改其字段,並且這些字段始終是私有的並建議是最終的),例如String,但不能更改當前的String,但是您可以返回一個新的String,即:

String s = "some text";
s.substring(0,4);
System.out.println(s); // still printing "some text"
String a = s.substring(0,4);
System.out.println(a); // prints "some"



str第一次引用的str對像沒有改變,你所做的只是使str指向一個新的字符串對象。




字符串不可變的 。 這意味著我們只能改變參考

String a = "a";
System.out.println("String a is referencing to "+a); // Output: a

a.concat("b");
System.out.println("String a is referencing to "+a); // Output: a

a = a.concat("b");
System.out.println("String a has created a new reference and is now referencing to "+a); // Output: ab



像Linus Tolvards說的那樣:

談話很便宜。 讓我看看代碼

看看這個:

public class Test{
    public static void main(String[] args){

        String a = "Mississippi";
        String b = "Mississippi";//String immutable property (same chars sequence), then same object

        String c = a.replace('i','I').replace('I','i');//This method creates a new String, then new object
        String d = b.replace('i','I').replace('I','i');//At this moment we have 3 String objects, a/b, c and d

        String e = a.replace('i','i');//If the arguments are the same, the object is not affected, then returns same object

        System.out.println( "a==b? " + (a==b) ); // Prints true, they are pointing to the same String object

        System.out.println( "a: " + a );
        System.out.println( "b: " + b );

        System.out.println( "c==d? " + (c==d) ); // Prints false, a new object was created on each one

        System.out.println( "c: " + c ); // Even the sequence of chars are the same, the object is different
        System.out.println( "d: " + d );

        System.out.println( "a==e? " + (a==e) ); // Same object, immutable property
    }
}

輸出是

a==b? true
a: Mississippi
b: Mississippi
c==d? false
c: Mississippi
d: Mississippi
a==e? true

所以,請記住兩件事:

  • 字符串是不可變的,直到你應用一個操作並創建一個新的(c&d案例)的方法。
  • 如果兩個參數相同,Replace方法將返回相同的String對象



字符串不會改變,它的引用將會。 你將永恆性與final領域的概念混為一談。 如果一個字段被聲明為final ,一旦它被分配,它就不能被重新分配。




使用:

String s = new String("New String");
s.concat(" Added String");
System.out.println("String reference -----> "+s); // Output: String reference -----> New String

如果您在這裡看到我使用concat方法來更改原始字符串,即“New String”字符串為“Added String”,但仍得到前面的輸出,因此它證明您不能更改引用String類的對象,但是如果你通過StringBuilder類來完成這件事情,它將起作用。 它列在下面。

StringBuilder sb = new StringBuilder("New String");
sb.append(" Added String");
System.out.println("StringBuilder reference -----> "+sb);// Output: StringBuilder reference -----> New String Added String



超級遲到的答案,但想從Java的String類的作者提出一個簡潔的消息

字符串是不變的; 它們的值在創建後無法更改。 字符串緩衝區支持可變字符串。 因為String對像是不可變的,所以它們可以共享。

從這個文檔中可以得出,任何改變字符串的東西都會返回不同的對象(可能是新的或者是實際的和舊的)。 關於這個不太微妙的暗示應該來自函數簽名。 想一想,'為什麼他們在一個對像上返回一個對象而不是狀態?'。

public String replace(char oldChar, char newChar) 

還有一個來源使得這種行為是明確的(從替換函數文檔)

返回由newChar替換此字符串中出現的所有oldChar所產生的新字符串。

來源: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)

  • 作者Lee Boynton
  • 作者亞瑟範霍夫
  • 作者Martin Buchholz
  • 作者Ulf Zibis

來源:String的JavaDoc。




不變性我可以說的是,你不能改變字符串本身。 假設你有String x,其值是“abc”。 現在您不能更改字符串,也就是說,您無法更改“abc”中的任何字符。

如果必須更改字符串中的任何字符,則可以使用字符數組並對其進行變異或使用StringBuilder。

String x = "abc";
x = "pot";
x = x + "hj";
x = x.substring(3);
System.out.println(x);

char x1[] = x.toCharArray();
x1[0] = 's';
String y = new String(x1);
System.out.println(y);

輸出:

hj
sj





Links