ความไม่เปลี่ยนแปลงของ 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"); // printsintern(): นำ 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")); // 42String เป็นคลาสสุดท้าย
คลาส 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 ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- ความไม่เปลี่ยนแปลงของ String และ String Pool
- StringBuilder สำหรับการต่อสตริงอย่างมีประสิทธิภาพ
- บล็อกข้อความและ String.format
- นิพจน์ทั่วไปด้วย Pattern และ Matcher