0Pricing
Java Academy · บทเรียน

ความไม่เปลี่ยนแปลงของ String และ String Pool

ทำความเข้าใจว่าเหตุใด String จึงไม่เปลี่ยนแปลง วิธีทำงานของ string pool และควรใช้ == หรือ equals เมื่อใด

ความไม่เปลี่ยนแปลงของ String และ String Pool เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

ความไม่เปลี่ยนแปลงของ String และพูล String

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

เหตุใด String จึงไม่เปลี่ยนแปลง

อ็อบเจ็กต์ String ไม่สามารถแก้ไขได้หลังจากสร้างขึ้น การดำเนินการใด ๆ ที่ดูเหมือนว่า "เปลี่ยนแปลง" String จะสร้างอ็อบเจ็กต์ String ใหม่จริง ๆ ซึ่งช่วยให้เกิดการใช้ร่วมกัน ความปลอดภัยสำหรับเธรด และการแคช hashCode

String s = "hello";
s.toUpperCase(); // creates a new String, does NOT modify s
System.out.println(s); // still "hello"

String upper = s.toUpperCase(); // must capture the result
System.out.println(upper); // HELLO

พูล String (การทำอินเทอร์น)

ลิเทอรัล String จะถูกจัดเก็บไว้ใน พูล String (ส่วนพิเศษของฮีป) ลิเทอรัลสองรายการที่มีเนื้อหาเหมือนกันจะใช้อ็อบเจ็กต์เดียวกันร่วมกัน

String a = "hello"; // goes into pool
String b = "hello"; // same object from pool
String c = new String("hello"); // forces new object outside pool

System.out.println(a == b);       // true  (same pool reference)
System.out.println(a == c);       // false (different objects)
System.out.println(a.equals(c));  // true  (same content)

== เทียบกับ equals()

โปรดใช้ .equals() เพื่อเปรียบเทียบเนื้อหาของ String เสมอ ตัวดำเนินการ == จะตรวจสอบว่าตัวแปรสองตัวชี้ไปยังอ็อบเจ็กต์เดียวกันหรือไม่ (ความเท่ากันของการอ้างอิง)

String input = new String("admin"); // from user input, not pooled
String role  = "admin";

// Dangerous: fails because different objects
if (input == role) System.out.println("Same"); // not printed!

// Correct: compares content
if (input.equals(role)) System.out.println("Equal!"); // prints

// Null-safe: put constant first to avoid NPE
if ("admin".equals(input)) System.out.println("Admin"); // prints

intern(): นำ String เข้าพูลด้วยตนเอง

String.intern() บังคับให้ String เข้าไปอยู่ในพูลและส่งคืนการอ้างอิงในพูล โดยทั่วไปแล้ว Java สมัยใหม่แทบไม่จำเป็นต้องใช้วิธีนี้

String s1 = new String("interned");
String s2 = s1.intern();
String s3 = "interned"; // already in pool

System.out.println(s2 == s3); // true (both point to pool)
System.out.println(s1 == s3); // false (s1 is off-pool)

// Modern use: prefer String.intern() only when you need
// identity-based caching with thousands of repeated strings

พฤติกรรมการต่อ String

การต่อด้วย + จะสร้างอ็อบเจ็กต์ String ใหม่ ภายในลูป การดำเนินการนี้มีความซับซ้อน O(n²) คอมไพเลอร์จะปรับปรุงนิพจน์เดี่ยวให้เหมาะสม แต่ไม่ปรับปรุงการต่อที่อยู่ในลูป

// Compiler optimizes this to a StringBuilder automatically:
String result = "Hello, " + "World" + "!";

// In loops: compiler does NOT optimize — use StringBuilder explicitly!
List<String> words = List.of("a", "b", "c", "d");
String bad = ""; // O(n^2) — new object each iteration
for (String w : words) bad += w;

StringBuilder sb = new StringBuilder();
for (String w : words) sb.append(w); // O(n) — efficient
String good = sb.toString();
System.out.println(good); // abcd

การเปรียบเทียบ String อย่างถูกต้อง

โปรดใช้ equals() เสมอ หากต้องการเปรียบเทียบโดยไม่คำนึงถึงตัวพิมพ์เล็กใหญ่ ให้ใช้ equalsIgnoreCase() ส่วน compareTo() ใช้สำหรับการเรียงลำดับตามลำดับพจนานุกรม

String a = "Java";
String b = "java";

System.out.println(a.equals(b));             // false
System.out.println(a.equalsIgnoreCase(b));   // true
System.out.println(a.compareToIgnoreCase(b)); // 0 (equal)
System.out.println(a.compareTo(b));           // negative (J < j in Unicode)

การแคชแฮชโค้ดของ String

เนื่องจาก String ไม่สามารถเปลี่ยนแปลงได้ Java จึงแคช hashCode หลังจากเรียกใช้ครั้งแรก การเรียกครั้งถัดไปจะส่งคืนค่าที่แคชไว้ ทำให้ String มีประสิทธิภาพสูงเมื่อใช้เป็นคีย์ของ HashMap

String key = "product:12345";
// hashCode computed once and cached:
int h1 = key.hashCode();
int h2 = key.hashCode(); // returns cached value
System.out.println(h1 == h2); // true

// Strings are ideal HashMap keys because:
// 1. hashCode is consistent (immutable content)
// 2. hashCode is cached (fast repeated lookups)
// 3. equals is well-defined (content-based)
Map<String, Integer> map = new HashMap<>();
map.put("key", 42);
System.out.println(map.get("key")); // 42

String เป็นคลาสสุดท้าย

คลาส String เป็น final จึงไม่สามารถสร้างคลาสย่อยได้ การกำหนดเช่นนี้รับประกันว่าจะไม่มีคลาสย่อยใดทำลายความไม่เปลี่ยนแปลงหรือความสอดคล้องของ hashCode

// String is final — this will not compile:
// class MutableString extends String {} // compile error

// You cannot override String behavior.
// If you need custom string-like behavior, use a wrapper:
record ProductSku(String value) {
    ProductSku { if (!value.matches("[A-Z]{3}-[0-9]{4}")) throw new IllegalArgumentException(); }
    @Override public String toString() { return value; }
}

String.format เทียบกับการต่อ

สำหรับ String ที่ประกอบด้วยหลายส่วน ควรใช้ String.format() หรือบล็อกข้อความแทนการต่อ เพื่อให้อ่านได้ชัดเจนและแปลเป็นภาษาอื่นได้ง่ายขึ้น

String name = "Alice";
int age = 30;
double score = 97.5;

// Concatenation — harder to read with many parts
String bad = "User: " + name + ", Age: " + age + ", Score: " + score;

// String.format — clear placeholders
String good = String.format("User: %s, Age: %d, Score: %.1f", name, age, score);

System.out.println(good);
// User: Alice, Age: 30, Score: 97.5

การดำเนินการกับ String ที่ปลอดภัยต่อค่า null

การดำเนินการกับ String หลายอย่างจะโยน NPE หาก String เป็น null โปรดใช้รูปแบบการเขียนแบบป้องกันหรือ String.valueOf() เพื่อจัดการกับ null อย่างปลอดภัย

String value = null;

// Null-safe length check
int len = (value != null) ? value.length() : 0;
System.out.println(len); // 0

// Null-safe comparison (put constant first)
boolean isAdmin = "admin".equals(value); // false, no NPE

// String.valueOf converts null to "null" string
System.out.println(String.valueOf(value)); // "null"
System.out.println(Objects.toString(value, "default")); // "default"

ตรวจสอบอย่างรวดเร็ว

โค้ดต่อไปนี้จะแสดงผลอะไร

String a = "hello";
String b = new String("hello");
System.out.println(a.equals(b));
System.out.println(a == b);

สรุป: ความไม่เปลี่ยนแปลงของ String และพูล String

ประเด็นสำคัญ:

  • String ไม่สามารถเปลี่ยนแปลงได้ การดำเนินการจะส่งคืนอ็อบเจ็กต์ String ใหม่และไม่แก้ไขอ็อบเจ็กต์เดิม
  • ลิเทอรัล String จะถูกเก็บในพูล ลิเทอรัลสองรายการที่มีเนื้อหาเหมือนกันจะใช้อ็อบเจ็กต์เดียวกัน
  • โปรดใช้ .equals() เพื่อเปรียบเทียบเนื้อหาของ String เสมอ ส่วน == จะเปรียบเทียบการอ้างอิงอ็อบเจ็กต์
  • ใช้ equalsIgnoreCase() สำหรับการเปรียบเทียบที่ไม่คำนึงถึงตัวพิมพ์เล็กใหญ่
  • การต่อ String ในลูปมีความซับซ้อน O(n²) โปรดใช้ StringBuilder เพื่อประสิทธิภาพ
  • String จะแคช hashCode ไว้ ทำให้มีประสิทธิภาพและปลอดภัยเมื่อใช้เป็นคีย์ของ HashMap

คำถามที่พบบ่อย

บทเรียน “ความไม่เปลี่ยนแปลงของ String และ String Pool” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “ความไม่เปลี่ยนแปลงของ String และ String Pool” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “ความไม่เปลี่ยนแปลงของ String และ String Pool”

ทำความเข้าใจว่าเหตุใด String จึงไม่เปลี่ยนแปลง วิธีทำงานของ string pool และควรใช้ == หรือ equals เมื่อใด คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 1 จากทั้งหมด 4 บทเรียน

บทเรียน “ความไม่เปลี่ยนแปลงของ String และ String Pool” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม

ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. ความไม่เปลี่ยนแปลงของ String และ String Pool
  2. StringBuilder สำหรับการต่อสตริงอย่างมีประสิทธิภาพ
  3. บล็อกข้อความและ String.format
  4. นิพจน์ทั่วไปด้วย Pattern และ Matcher
← กลับไปที่ Java Academy