การเปลี่ยนไม่ได้ของสตริงใน Java


218

ลองพิจารณาตัวอย่างต่อไปนี้

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!") และstrจุดอ้างอิงไปยังวัตถุอื่นหลังจากreplace()วิธีการหรือไม่


STR เป็นเพียงการอ้างอิงที่ไม่ได้คัดค้านตัวเอง
ahmednabil88

ฉันหวังว่านี่จะช่วยpushkarrajpujari.com/article/strings-in-java
Pushkarraj Pujari

คำตอบ:


316

strไม่ใช่วัตถุ แต่เป็นการอ้างอิงถึงวัตถุ "Hello"และ"Help!"เป็นสองStringวัตถุที่แตกต่าง ดังนั้นstr ชี้ไปที่สตริง คุณสามารถเปลี่ยนสิ่งที่มันชี้ไปแต่ไม่ว่าที่มันชี้ที่

ใช้รหัสนี้เช่น:

String s1 = "Hello";
String s2 = s1;
// s1 and s2 now point at the same string - "Hello"

ตอนนี้มีอะไรที่1เราสามารถทำได้เพื่อที่จะส่งผลกระทบต่อมูลค่าของs1 s2พวกเขาอ้างถึงวัตถุเดียวกัน - สตริง"Hello"- แต่วัตถุนั้นไม่เปลี่ยนรูปและดังนั้นจึงไม่สามารถเปลี่ยนแปลงได้

หากเราทำสิ่งนี้:

s1 = "Help!";
System.out.println(s2); // still prints "Hello"

ที่นี่เราเห็นความแตกต่างระหว่างการกลายพันธุ์วัตถุและการเปลี่ยนแปลงการอ้างอิง s2ยังคงชี้ไปที่วัตถุเดียวกันกับที่เราเริ่มตั้งค่าs1ให้ชี้ไปที่ การตั้งค่าs1ให้"Help!"เปลี่ยนการอ้างอิงเท่านั้นในขณะที่Stringวัตถุที่อ้างถึงเดิมนั้นยังคงไม่เปลี่ยนแปลง

ถ้าสตริงก็ไม่แน่นอนว่าเราสามารถทำอะไรเช่นนี้

String s1 = "Hello";
String s2 = s1;
s1.setCharAt(1, 'a'); // Fictional method that sets character at a given pos in string
System.out.println(s2); // Prints "Hallo"

แก้ไขเพื่อตอบสนองต่อการแก้ไขของ OP:

หากคุณดูซอร์สโค้ดสำหรับ String.replace (char, char) (ยังมีอยู่ใน src.zip ในไดเรกทอรีการติดตั้ง JDK ของคุณ - เคล็ดลับสำหรับการดูคือเมื่อใดก็ตามที่คุณสงสัยว่ามีบางสิ่งที่ใช้งานได้จริง) คุณจะเห็นว่า มันเป็นดังต่อไปนี้:

  • หากมีสิ่งหนึ่งหรือมากกว่าการเกิดขึ้นของoldCharในสตริงปัจจุบันทำสำเนาของสตริงปัจจุบันที่เกิดขึ้นทั้งหมดในจะถูกแทนที่ด้วยoldCharnewChar
  • หากoldCharไม่มีอยู่ในสตริงปัจจุบันให้ส่งคืนสตริงปัจจุบัน

ใช่"Mississippi".replace('i', '!')สร้างStringวัตถุใหม่ อีกครั้งถือต่อไปนี้:

String s1 = "Mississippi";
String s2 = s1;
s1 = s1.replace('i', '!');
System.out.println(s1); // Prints "M!ss!ss!pp!"
System.out.println(s2); // Prints "Mississippi"
System.out.println(s1 == s2); // Prints "false" as s1 and s2 are two different objects

การบ้านของคุณตอนนี้คือการดูว่าโค้ดข้างต้นทำอะไรถ้าคุณเปลี่ยนs1 = s1.replace('i', '!');เป็นs1 = s1.replace('Q', '!');:)


1 ที่จริงแล้วมันเป็นไปได้ที่จะกลายพันธุ์สตริง (และวัตถุที่ไม่เปลี่ยนรูปอื่น ๆ ) มันต้องมีการไตร่ตรองและมีอันตรายมากและไม่ควรนำมาใช้เว้นแต่คุณจะสนใจที่จะทำลายโปรแกรม


15
+1 สำหรับวิธีสวมมันแสดงให้เห็นถึงความแตกต่างระหว่างวัตถุที่ไม่เปลี่ยนรูปและอื่น ๆ
Zappi

1
ขอบคุณ gustafc สำหรับตัวอย่างที่ถูกต้องและคำอธิบายที่ชัดเจน .... แต่คุณสามารถตอบส่วนที่แก้ไขในคำถามได้มั้ย นั่นจะทำให้ความเข้าใจของฉันชัดเจน
Light_handle

17
ฉันไม่เคยเห็นคำตอบเช่นนี้มาก่อน พูดคุยทุกรายละเอียด
Michael 'Maik' Ardan

+1 นี่คือความคิดวัตถุที่ไม่เปลี่ยนรูปแบบใน java เป็นเหมือนการคัดลอกโดยค่าคุณสามารถมี 2 การอ้างอิงถึงสตริง แต่คุณควรพิจารณาพวกเขา 2 สายแยกต่างหากเพราะมันไม่เปลี่ยนรูปและการทำงานกับหนึ่งในนั้นจะไม่ส่งผลกระทบต่อ อื่น ๆ
Khaled.K

1
Java ยิ่งคุณคิดว่าคุณรู้มากเท่าไหร่คุณก็ยิ่งรู้จักน้อยเท่านั้น
zeeshan

23

วัตถุที่strการอ้างอิงสามารถเปลี่ยนแปลงได้ แต่Stringตัววัตถุจริงไม่สามารถทำได้

Stringวัตถุที่มีสตริง"Hello"และ"Help!"ไม่สามารถเปลี่ยนค่าของพวกเขาดังนั้นพวกเขาจะไม่เปลี่ยนรูป

ความไม่เปลี่ยนแปลงของStringวัตถุไม่ได้หมายความว่าการอ้างอิงที่ชี้ไปยังวัตถุนั้นไม่สามารถเปลี่ยนแปลงได้

วิธีหนึ่งที่สามารถป้องกันการstrอ้างอิงจากการเปลี่ยนแปลงคือการประกาศเป็นfinal:

final String STR = "Hello";

ตอนนี้พยายามที่จะกำหนดอีกStringเพื่อSTRจะทำให้เกิดการรวบรวมข้อผิดพลาด


แต่ในกรณีนี้วัตถุสตริงคือ 'str' ซึ่งประกอบด้วยค่า 'Hello' ก่อนแล้วจึงได้รับค่าใหม่ 'Help!' คุณหมายถึงอะไรโดย "วัตถุสตริงที่มีสตริง" Hello "และ" Help! "ไม่สามารถเปลี่ยนค่าของพวกเขาดังนั้นพวกเขาจะไม่เปลี่ยนรูปได้" ??? ให้อภัยฉันถ้านี่เป็นคำถามงี่เง่า แต่ iv ได้ไปล้างมัน ...
Light_handle

2
คุณเคยลองทุกโปรแกรมใน C หรือไม่? เพียงอ่านไพรเมอร์บนพอยน์เตอร์แล้วคุณจะเข้าใจคำตอบของ coobird ได้อย่างสมบูรณ์แบบ
ไรอัน Fernandes

ดู ... นี่คือสิ่งที่ฉันต้องการหลีกเลี่ยง ... ฉันรู้ว่าคุณเป็นโปรแกรมเมอร์ที่ยอดเยี่ยม ... และฉันแค่พยายามเรียนรู้จาวาที่นี่ ... ดังนั้นหากคุณสามารถตอบคำถามของฉันได้อย่างถูกต้องกรุณาตอบด้วย .. .
Light_handle

คุณกำลังสร้างความสับสนในการอ้างอิงและวัตถุ - strไม่ใช่ "วัตถุ" เป็นการอ้างอิงถึงวัตถุ หากคุณString str = "Hello";ตามมาโดยที่String anotherReference = str;คุณไม่มีวัตถุ String 2 ตัวคุณจะมีหนึ่งวัตถุ (ตัวอักษร "Hello") และการอ้างอิง 2 รายการกับมัน ( strและanotherReference)
เนท

ฉันไม่มีสิทธิ์ในการแก้ไข แต่ถ้าฉันทำฉันจะแก้ไข coobirds ประโยคที่ 1 เป็น: "การอ้างอิง str สามารถเปลี่ยนแปลงได้ แต่วัตถุ String จริงไม่สามารถทำได้"
j3App

10

Light_handle ผมขอแนะนำให้คุณใช้เวลาในการอ่านของถ้วยขนาด - เรื่องราวเกี่ยวกับตัวแปรและผ่านโดยราคาโปรด (ถ้วยขนาดต่อ) วิธีนี้จะช่วยได้มากเมื่ออ่านบทความด้านบน

คุณอ่านมาแล้วเหรอ? ใช่. ดี.

String str = new String();

สิ่งนี้จะสร้าง "การควบคุมระยะไกล" ใหม่ที่เรียกว่า " str" และตั้งค่านั้นเป็นค่าnew String()(หรือ"")

เช่นในความทรงจำสิ่งนี้จะสร้าง:

str --- > ""

str  = "Hello";

นี้จากนั้นจะมีการเปลี่ยนแปลงการควบคุมระยะไกล " str" ""แต่ไม่ได้ปรับเปลี่ยนสายเดิม

เช่นในความทรงจำสิ่งนี้จะสร้าง:

str -+   ""
     +-> "Hello"

str = "Help!";

สิ่งนี้จะเปลี่ยนรีโมตคอนโทรล " str" แต่ไม่ได้แก้ไขสตริงเดิม""หรือวัตถุที่รีโมตคอนโทรลชี้ไป

เช่นในความทรงจำสิ่งนี้จะสร้าง:

str -+   ""
     |   "Hello"
     +-> "Help!"

"" และ "Hello" เก็บขยะไหม
Prabin Timsina

@PrabinTimsina นี่ควรเป็นคำถามใหม่ มันมีคำตอบ: stackoverflow.com/questions/15324143/ …
Michael Lloyd Lee mlk

9

ช่วยแบ่งมันออกเป็นบางส่วน

String s1 = "hello";

คำสั่งนี้สร้างสตริงที่ประกอบด้วยhelloและใช้พื้นที่ในหน่วยความจำเช่นในConstant String Poolและกำหนดให้กับวัตถุอ้างอิงs1

String s2 = s1;

คำสั่งนี้กำหนดสตริงเดียวกันสวัสดีให้กับการอ้างอิงใหม่s2

         __________
        |          |
s1 ---->|  hello   |<----- s2
        |__________| 

การอ้างอิงทั้งสองชี้ไปที่สตริงเดียวกันดังนั้นให้ส่งออกค่าเดียวกันดังนี้

out.println(s1);    // o/p: hello
out.println(s2);    // o/p: hello

แม้ว่าStringคือไม่เปลี่ยนรูปได้รับมอบหมายสามารถเป็นไปได้เพื่อให้s1ตอนนี้จะหมายถึงค่าใหม่สแต็ค

s1 = "stack";    
         __________
        |          |
s1 ---->|  stack   |
        |__________|

แต่สิ่งที่เกี่ยวกับวัตถุs2ซึ่งชี้ไปที่สวัสดีมันจะเป็นอย่างที่มันเป็น

         __________
        |          |
s2 ---->|  hello   |
        |__________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello

เนื่องจาก String เป็นJava Virtual Machine ที่ไม่เปลี่ยนรูปแบบจะไม่อนุญาตให้เราแก้ไข string s1ด้วยวิธีการ มันจะสร้างวัตถุ String ใหม่ทั้งหมดในกลุ่มดังนี้

s1.concat(" overflow");

                 ___________________
                |                   |
s1.concat ----> |  stack overflow   |
                |___________________|

out.println(s1);    // o/p: stack
out.println(s2);    // o/p: hello
out.println(s1.concat); // o/p: stack overflow

หมายเหตุถ้า String จะไม่แน่นอนจากนั้นจะได้รับการออก

out.println(s1);    // o/p: stack overflow

ตอนนี้คุณอาจประหลาดใจว่าทำไม String ถึงมีวิธีการเช่นconcat ()เพื่อแก้ไข ตัวอย่างต่อไปนี้จะล้างความสับสนของคุณ

s1 = s1.concat(" overflow");

ที่นี่เรากำลังกำหนดค่าที่แก้ไขของสตริงกลับไปที่การอ้างอิงs1

         ___________________
        |                   |
s1 ---->|  stack overflow   |
        |___________________|


out.println(s1);    // o/p: stack overflow
out.println(s2);    // o/p: hello

นั่นเป็นเหตุผลที่ Java ตัดสินใจให้ String เป็นคลาสสุดท้ายมิฉะนั้นใคร ๆ ก็สามารถแก้ไขและเปลี่ยนแปลงค่าของสตริงได้ หวังว่านี่จะช่วยได้นิดหน่อย


6

วัตถุสตริงที่ถูกอ้างอิงครั้งแรกโดยstrไม่มีการเปลี่ยนแปลงสิ่งที่คุณทำคือการstrอ้างอิงถึงวัตถุสตริงใหม่


5

สตริงจะไม่เปลี่ยนแปลงการอ้างอิงถึงมันจะ คุณกำลังสับสนกับแนวคิดที่finalไม่เปลี่ยนแปลง หากมีการประกาศฟิลด์ว่าfinalเมื่อได้รับการกำหนดแล้วจะไม่สามารถกำหนดฟิลด์นั้นได้อีก


5

เกี่ยวกับส่วนแทนที่ของคำถามลองสิ่งนี้:

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!

4

แม้ว่าจาวาพยายามที่จะเพิกเฉย แต่strก็ไม่มีอะไรมากไปกว่าตัวชี้ ซึ่งหมายความว่าเมื่อคุณเขียนครั้งแรกที่str = "Hello";คุณจะสร้างวัตถุที่strจุดที่จะต้อง เมื่อคุณมอบหมายstrโดยการเขียนstr = "Help!";วัตถุใหม่จะถูกสร้างขึ้นและ"Hello"วัตถุเก่าจะถูกเก็บขยะเมื่อใดก็ตามที่จาวารู้สึกเช่นนั้น


3

ความไม่สามารถเปลี่ยนแปลงได้หมายความว่าค่าของวัตถุที่ยกตัวอย่างไม่สามารถเปลี่ยนแปลงได้คุณไม่สามารถเปลี่ยน "Hello" เป็น "Help!"

ตัวแปร str คือการอ้างอิงไปยังวัตถุเมื่อคุณกำหนดค่าใหม่ให้กับ str คุณไม่ได้เปลี่ยนค่าของวัตถุที่อ้างอิงคุณกำลังอ้างอิงวัตถุอื่น


3

คลาส String ไม่เปลี่ยนรูปและคุณไม่สามารถเปลี่ยนค่าของวัตถุที่ไม่เปลี่ยนรูป แต่ในกรณีของ String หากคุณเปลี่ยนค่าของสตริงจะสร้างสตริงใหม่ในสตริงพูลและกว่าสตริงของคุณอ้างอิงกับค่านั้นไม่ใช่สตริงเก่า ดังนั้นโดยวิธีนี้สตริงไม่เปลี่ยนรูป ให้นำตัวอย่างของคุณ

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

มันจะสร้างหนึ่งสตริง"Mississippi"และจะเพิ่มลงใน String pool ดังนั้นตอนนี้ str กำลังชี้ไปที่ Mississippi

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

แต่หลังจากการดำเนินการข้างต้นสตริงอื่นจะถูกสร้าง"M! ss! ss! pp!" และมันจะถูกเพิ่มลงใน String pool และตอนนี้ str กำลังชี้ไปที่ M! ss! ss! pp! ไม่ใช่ Mississippi

ดังนั้นโดยวิธีนี้เมื่อคุณจะเปลี่ยนค่าของวัตถุสตริงมันจะสร้างวัตถุอีกหนึ่งและจะเพิ่มไปยังสระว่ายน้ำสตริง

ให้มีอีกตัวอย่างหนึ่ง

String s1 = "Hello"; 
String s2 = "World"; 
String s = s1 + s2;

สามบรรทัดด้านบนนี้จะเพิ่มวัตถุสามรายการของสตริงลงในสตริงพูล
1) สวัสดี
2) โลก
3) HelloWorld


2

ใช้:

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

หากคุณเห็นที่นี่ฉันใช้concatวิธีการเปลี่ยนสตริงเดิมนั่นคือ "สตริงใหม่" กับสตริง "สตริงเพิ่ม" แต่ยังฉันได้รับผลลัพธ์ก่อนหน้าดังนั้นจึงพิสูจน์ได้ว่าคุณไม่สามารถเปลี่ยนการอ้างอิงของวัตถุ ของคลาส 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

2

เช่นเดียวกับ 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)
  • เมธอด replace ส่งคืนอ็อบเจ็กต์ String เดียวกันหากพารามิเตอร์ทั้งสองเหมือนกัน

0

สำหรับผู้ที่สงสัยว่าจะทำลายการเปลี่ยนแปลงไม่ได้สตริงใน Java ...

รหัส

import java.lang.reflect.Field;

public class StringImmutability {
    public static void main(String[] args) {
        String str1 = "I am immutable";
        String str2 = str1;

        try {
            Class str1Class = str1.getClass();
            Field str1Field = str1Class.getDeclaredField("value");

            str1Field.setAccessible(true);
            char[] valueChars = (char[]) str1Field.get(str1);

            valueChars[5] = ' ';
            valueChars[6] = ' ';

            System.out.println(str1 == str2);
            System.out.println(str1);
            System.out.println(str2);           
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

    }
}

เอาท์พุต

true
I am   mutable
I am   mutable

0

สตริงคือไม่เปลี่ยนรูป ซึ่งหมายความว่าเราสามารถเปลี่ยนการอ้างอิงเท่านั้น


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

0

ใน Java วัตถุโดยทั่วไปจะเข้าถึงได้โดยอ้างอิง ในส่วนของโค้ด str ของคุณคือการอ้างอิงซึ่งถูกกำหนดให้กับ "Hello" เป็นครั้งแรก (วัตถุที่สร้างขึ้นโดยอัตโนมัติหรือดึงมาจากสระว่ายน้ำคงที่ ) จากนั้นคุณมอบหมายวัตถุอื่น "Help!" อ้างอิงเดียวกัน จุดที่ควรทราบคือการอ้างอิงเหมือนกันและปรับเปลี่ยน แต่วัตถุแตกต่างกัน อีกอย่างในรหัสของคุณที่คุณเข้าถึงวัตถุสามอย่าง

  1. เมื่อคุณเรียกสตริงใหม่ ()
  2. เมื่อคุณมอบหมาย "hello"
  3. เมื่อคุณกำหนด "ความช่วยเหลือ!"

การเรียกสตริงใหม่ () สร้างวัตถุใหม่แม้ว่าจะมีอยู่ในกลุ่มสตริดังนั้นโดยทั่วไปไม่ควรใช้ ในการใส่สตริงที่สร้างจาก String ใหม่ () ลงในพูลสตริงคุณสามารถลองใช้intern()เมธอดได้

ฉันหวังว่านี่จะช่วยได้.


0

การเปลี่ยนไม่ได้ฉันสามารถพูดได้คือคุณไม่สามารถเปลี่ยน String ได้ สมมติว่าคุณมี 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

0

หรือคุณสามารถลอง:

public class Tester
{
public static void main(String[] args)
{
 String str = "Mississippi"; 
 System.out.println(str); // prints Mississippi 
 System.out.println(str.hashCode());

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

นี่จะแสดงการเปลี่ยนแปลงของแฮชโค้ด


0

สายอักขระไม่เปลี่ยนรูปหมายความว่าคุณไม่สามารถเปลี่ยนวัตถุเอง แต่คุณสามารถเปลี่ยนการอ้างอิงไปยังวัตถุ เมื่อคุณเรียกว่า a = "ty" คุณจะเปลี่ยนการอ้างอิงของ a เป็นวัตถุใหม่ที่สร้างขึ้นโดย "ty" ของตัวอักษร String การเปลี่ยนวัตถุหมายถึงการใช้วิธีการเพื่อเปลี่ยนหนึ่งในฟิลด์ของมัน (หรือฟิลด์นั้นเป็นแบบสาธารณะและไม่ใช่ครั้งสุดท้ายเพื่อให้สามารถอัปเดตจากภายนอกโดยไม่ต้องเข้าถึงพวกเขาผ่านวิธีการ) ตัวอย่างเช่น:

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

ในขณะที่อยู่ในคลาสที่ไม่เปลี่ยนรูป (ประกาศเป็นขั้นสุดท้ายเพื่อป้องกันการปรับเปลี่ยนผ่านการสืบทอด) (วิธีการไม่สามารถแก้ไขฟิลด์ได้และฟิลด์ยังเป็นแบบส่วนตัวเสมอและแนะนำให้เป็นขั้นสุดท้าย) ตัวอย่างเช่น 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"

0

ความไม่เปลี่ยนรูปในที่นี้หมายความว่าอินสแตนซ์นั้นสามารถชี้ไปที่การอ้างอิงอื่น ๆ แต่เนื้อหาดั้งเดิมของสตริงจะไม่ถูกแก้ไขในการอ้างอิงดั้งเดิม ให้ฉันอธิบายตามตัวอย่างแรกที่คุณให้มา str แรกชี้ไปที่ "Hello" มันตกลงมาถึงสิ่งนี้ ครั้งที่สองมันชี้ไปที่ "ช่วยเหลือ!" ที่นี่ str เริ่มชี้ไปที่ "ช่วยเหลือ!" และการอ้างอิงของสตริง "Hello" จะหายไปและเราไม่สามารถรับกลับมาได้

ในความเป็นจริงเมื่อ str จะพยายามแก้ไขเนื้อหาที่มีอยู่แล้วสตริงใหม่จะถูกสร้างขึ้นและ str จะเริ่มชี้ไปที่การอ้างอิงนั้น ดังนั้นเราจะเห็นว่าสตริงที่การอ้างอิงดั้งเดิมไม่ได้ถูกแก้ไข แต่มันปลอดภัยที่การอ้างอิงและอินสแตนซ์ของวัตถุเริ่มชี้ไปที่การอ้างอิงที่แตกต่างกันดังนั้นการเปลี่ยนแปลงไม่ได้จึงประหยัดได้


0

สุดสายถึงคำตอบ แต่ต้องการที่จะนำข้อความที่กระชับจากผู้เขียนของคลาส String ใน Java

เงื่อนไขคงที่; ค่าของพวกเขาไม่สามารถเปลี่ยนแปลงได้หลังจากที่พวกเขาถูกสร้างขึ้น สตริงบัฟเฟอร์สนับสนุนสตริงที่ไม่แน่นอน เนื่องจากอ็อบเจกต์ String ไม่สามารถเปลี่ยนแปลงได้จึงสามารถแชร์ได้

มันสามารถได้รับจากเอกสารนี้ว่าสิ่งที่เปลี่ยนแปลงสตริงส่งกลับวัตถุที่แตกต่างกัน (ซึ่งอาจเป็นใหม่หรือฝึกงานและเก่า) คำใบ้ที่ไม่ลึกซึ้งเกี่ยวกับเรื่องนี้ควรมาจากฟังก์ชันของลายเซ็น คิดว่า 'ทำไมพวกเขาทำให้ฟังก์ชั่นบนวัตถุกลับวัตถุแทนสถานะ?'

public String replace(char oldChar, char newChar) 

อีกแหล่งที่หนึ่งซึ่งทำให้ลักษณะการทำงานนี้ชัดเจน (จากการแทนที่เอกสารประกอบฟังก์ชัน)

ส่งคืนสตริงใหม่ที่เป็นผลมาจากการแทนที่ oldChar ทั้งหมดที่เกิดขึ้นในสตริงนี้ด้วย newChar

ที่มา: https://docs.oracle.com/javase/7/docs/api/java/lang/String.html#replace(char,%20char)

  • ผู้เขียน Lee Boynton
  • ผู้เขียน Arthur van Hoff
  • ผู้เขียนมาร์ติน Buchholz
  • ผู้แต่ง Ulf Zibis

ที่มา: JavaDoc ของ String


0

สตริง Object - เมธอดเองถูกทำให้เป็น "ไม่เปลี่ยนรูป" การกระทำนี้ไม่ก่อให้เกิดการเปลี่ยนแปลง: "letters.replace (" 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);

// แฮชโค้ดของ Object String จะไม่เปลี่ยนแปลง


0

ถ้าHELLOเป็น String ของคุณแล้วคุณจะไม่สามารถเปลี่ยนไปHELLO HILLOคุณสมบัตินี้เรียกว่าคุณสมบัติไม่เปลี่ยนรูป

คุณสามารถมีตัวแปร String ของตัวชี้หลายตัวชี้ HELLO String

แต่ถ้า HELLO เป็นถ่าน Array คุณสามารถเปลี่ยน HELLO เป็น HILLO ได้ เช่น,

char[] charArr = 'HELLO';
char[1] = 'I'; //you can do this

ภาษาการเขียนโปรแกรมมีตัวแปรข้อมูลที่เปลี่ยนแปลงไม่ได้ดังนั้นจึงสามารถใช้เป็นคีย์ในคู่ของคีย์, คู่ของค่า


0

ฉันจะอธิบายด้วยตัวอย่างง่ายๆ


พิจารณาอาร์เรย์อักขระใด ๆ : เช่น char a [] = {'h', 'e', ​​'l', 'l', 'o'}; และสตริง: String s = "hello";


ในอาเรย์ตัวละครเราสามารถดำเนินการเช่นการพิมพ์ตัวอักษรสามตัวสุดท้ายเท่านั้นโดยใช้ซ้ำอาร์เรย์; แต่ในสตริงเราต้องสร้างวัตถุ String ใหม่และคัดลอกสตริงย่อยที่ต้องการและที่อยู่ของมันจะอยู่ในวัตถุสตริงใหม่

เช่น

***String s="hello";
String s2=s.substrig(0,3);***

ดังนั้น s2 จะมี "hel";


-1

สตริงใน Java ในไม่เปลี่ยนรูปและสุดท้ายหมายความว่ามันไม่สามารถเปลี่ยนแปลงหรือแก้ไข:

กรณีที่ 1:

class TestClass{  
 public static void main(String args[]){  
   String str = "ABC";  
   str.concat("DEF");  
   System.out.println(str);  
 }  
} 

เอาท์พุต: ABC

เหตุผล: str อ้างอิงวัตถุจะไม่เปลี่ยนแปลงอันที่จริงวัตถุใหม่ "DEF" ถูกสร้างขึ้นซึ่งอยู่ในกลุ่มและไม่มีการอ้างอิงเลย (เช่นสูญหาย)

กรณีที่ 2:

class TestClass{  
 public static void main(String args[]){  
   String str="ABC";  
   str=str.concat("DEF");  
   System.out.println(str);  
 }  
}  

เอาท์พุท: ABCDEF

เหตุผล: ในกรณีนี้ str กำลังอ้างถึงวัตถุใหม่ "ABCDEF" ดังนั้นมันจึงพิมพ์ ABCDEF เช่นวัตถุ str ก่อนหน้า "ABC" จะหายไปในกลุ่มโดยไม่มีการอ้างอิง


-1

เนื่องจาก String ไม่สามารถเปลี่ยนแปลงได้ดังนั้นการเปลี่ยนแปลงจะไม่เกิดขึ้นหากคุณจะไม่กำหนดค่าที่ส่งคืนของฟังก์ชันให้กับสตริงดังนั้นในคำถามของคุณจะกำหนดค่าของฟังก์ชัน swap ที่ส่งคืนค่าให้กับ s

s = swap (s, n1, n2) จากนั้นค่าของสตริงจะเปลี่ยนไป

ฉันยังได้รับค่าไม่เปลี่ยนแปลงเมื่อฉันกำลังเขียนโปรแกรมเพื่อรับสตริงการเรียงสับเปลี่ยน (แม้ว่าจะไม่ได้ให้การเปลี่ยนลำดับทั้งหมด แต่นี่เป็นตัวอย่างสำหรับตอบคำถามของคุณ)

นี่คือตัวอย่าง

> 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();
> } }

แต่ฉันไม่ได้รับค่าที่เปลี่ยนแปลงของสตริงจากโค้ดด้านบนดังนั้นฉันกำหนดค่าที่ส่งคืนของฟังก์ชัน swap ให้กับสตริงและได้รับการเปลี่ยนแปลงค่าของสตริง หลังจากกำหนดค่าที่ส่งคืนฉันได้รับค่า permuted ของสตริง

/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; } }

-1
    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 แทนสตริงสามารถใช้เพื่อหลีกเลี่ยงปัญหานี้

สำหรับคำถามสุดท้ายของคุณ :: u จะมีหนึ่งการอ้างอิงและ 2 สายในสตริงพูล .. ยกเว้นการอ้างอิงจะชี้ไปที่ m! ss! ss! pp!

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.