สำหรับคำถามในชุดนี้ ทุกคนที่ศึกษา Java ควรเข้าใจ แน่นอนว่ามันไม่สำคัญว่าคุณจะเรียน Java เพื่อความสนุกสนานหรือไม่ หากคุณคิดว่าคุณผ่านระดับเริ่มต้นแล้ว แต่ยังไม่เข้าใจปัญหาเหล่านี้ดีพอ โปรดเพิ่มตัวเองเข้าทีมผู้เริ่มต้น
คำถามที่ 1: ฉันกำลังพูดถึงอะไร?
String s = "สวัสดีชาวโลก!";
หลายๆ คนเคยทำสิ่งนี้มาแล้ว แต่จริงๆ แล้วเราจะประกาศอะไรกันแน่ คำตอบคือ: สตริงที่มีเนื้อหา "Hello world!" คำตอบที่คลุมเครือดังกล่าวมักเป็นสาเหตุของแนวคิดที่ไม่ชัดเจน หากคุณให้คำตอบที่ถูกต้อง คนครึ่งหนึ่งคงจะตอบผิด
คำสั่งนี้ประกาศการอ้างอิงถึงวัตถุชื่อ "s" ซึ่งสามารถชี้ไปที่วัตถุประเภท String ใด ๆ ในปัจจุบันจะชี้ไปที่วัตถุประเภท String "Hello world!" นี่คือสิ่งที่เกิดขึ้นจริงๆ เราไม่ได้ประกาศวัตถุ String เราเพิ่งประกาศตัวแปรอ้างอิงที่สามารถชี้ไปที่วัตถุ String เท่านั้น ดังนั้น หากหลังจากประโยคเมื่อกี้นี้ หากคุณเรียกใช้ประโยคอื่น:
สตริงสตริง = s;
เราได้ประกาศการอ้างอิงอื่นที่สามารถชี้ไปที่วัตถุ String เท่านั้น ไม่มีการสร้างวัตถุที่สองที่ยังคงชี้ไปที่วัตถุต้นฉบับ นั่นคือมันชี้ไปที่วัตถุเดียวกันกับ s
คำถามที่ 2: อะไรคือความแตกต่างระหว่างวิธี "==" และวิธีเท่ากับ?
ตัวดำเนินการ == ใช้เพื่อเปรียบเทียบค่าของตัวแปรเพื่อความเท่าเทียมกันโดยเฉพาะ สิ่งที่เข้าใจง่ายกว่าคือ:
คัดลอกรหัสรหัสดังต่อไปนี้:
อินท์เอ=10;
อินท์ข=10;
แล้ว a==b จะเป็นจริง
แต่สิ่งที่เข้าใจยากคือ:
คัดลอกรหัสรหัสดังต่อไปนี้:
สตริง a=new String("foo");
สตริง b=สตริงใหม่("foo");
จากนั้น a==b จะคืนค่าเท็จ
ตามโพสต์ก่อนหน้านี้ ตัวแปรวัตถุเป็นข้อมูลอ้างอิงจริง ๆ และค่าของพวกมันชี้ไปที่ที่อยู่หน่วยความจำที่วัตถุนั้นตั้งอยู่ ไม่ใช่ตัววัตถุเอง ทั้ง a และ b ใช้โอเปอเรเตอร์ใหม่ ซึ่งหมายความว่าสองสตริงที่มีเนื้อหา "foo" จะถูกสร้างขึ้นในหน่วยความจำ เนื่องจากมี "สอง" สตริงเหล่านั้นจึงอยู่ที่ที่อยู่หน่วยความจำต่างกัน ค่าของ a และ b จริงๆ แล้วเป็นค่าของที่อยู่หน่วยความจำสองแห่งที่แตกต่างกัน ดังนั้นเมื่อใช้ตัวดำเนินการ "==" ผลลัพธ์จะเป็นเท็จ เป็นความจริงที่ว่าอ็อบเจ็กต์ที่ a และ b ชี้ไปมีเนื้อหา "foo" และควรเป็น "เท่ากัน" แต่ตัวดำเนินการ == ไม่เกี่ยวข้องกับการเปรียบเทียบเนื้อหาอ็อบเจ็กต์
การเปรียบเทียบเนื้อหาของอ็อบเจ็กต์คือสิ่งที่เมธอดเท่ากับทำ
ดูวิธีการใช้วิธีเท่ากับของวัตถุ Object:
คัดลอกรหัสรหัสดังต่อไปนี้:
บูลีนเท่ากับ (วัตถุ o) {
ส่งคืนสิ่งนี้==o;
-
วัตถุวัตถุใช้ตัวดำเนินการ == ตามค่าเริ่มต้น ดังนั้นหากคลาสที่คุณสร้างขึ้นเองไม่ได้แทนที่เมธอดเท่ากับ คลาสของคุณจะได้ผลลัพธ์เดียวกันโดยใช้เท่ากับและใช้ == จะเห็นได้ว่าวิธีเท่ากับของ Object ไม่บรรลุเป้าหมายที่วิธีเท่ากับควรบรรลุ นั่นคือเพื่อเปรียบเทียบว่าเนื้อหาของสองวัตถุเท่ากันหรือไม่ เนื่องจากผู้สร้างชั้นเรียนควรเป็นผู้กำหนดคำตอบ Object จึงฝากงานนี้ไว้กับผู้สร้างชั้นเรียน
ดูคลาสสุดขั้ว:
คัดลอกรหัสรหัสดังต่อไปนี้:
คลาสมอนสเตอร์{
เนื้อหาสตริงส่วนตัว
-
บูลีนเท่ากับ (วัตถุอื่น) { กลับจริง;}
-
ฉันแทนที่วิธีเท่ากับ การใช้งานนี้ทำให้การเปรียบเทียบระหว่างอินสแตนซ์ Monster คืนค่าเป็นจริงเสมอโดยไม่คำนึงถึงเนื้อหา
ดังนั้นเมื่อคุณใช้วิธีเท่ากับเพื่อพิจารณาว่าเนื้อหาของวัตถุเท่ากันหรือไม่ โปรดอย่ามองข้ามไป เพราะบางทีคุณอาจคิดว่ามันเท่าเทียมกัน แต่ผู้เขียนคลาสนี้กลับไม่คิดเช่นนั้น และการใช้วิธีการเท่ากับของคลาสจะถูกควบคุมโดยเขา หากคุณต้องการใช้วิธีเท่ากับ หรือใช้คอลเลกชันตามรหัสแฮช (HashSet, HashMap, HashTable) โปรดตรวจสอบเอกสาร java เพื่อยืนยันว่ามีการใช้ตรรกะเท่ากับของคลาสนี้อย่างไร
คำถามที่ 3: สตริงมีการเปลี่ยนแปลงหรือไม่
เลขที่ เนื่องจาก String ได้รับการออกแบบให้เป็นคลาสที่ไม่เปลี่ยนรูป วัตถุทั้งหมดจึงเป็นวัตถุที่ไม่เปลี่ยนรูป โปรดดูรหัสต่อไปนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
สตริง s = "สวัสดี";
s = s + "โลก!";
เป้าหมายที่ชี้โดย s เปลี่ยนไปหรือไม่? ข้อสรุปนี้สามารถสรุปได้ง่าย ๆ จากข้อสรุปในบทความแรกของซีรี่ส์นี้ มาดูกันว่าเกิดอะไรขึ้น ในโค้ดนี้ s เดิมชี้ไปที่วัตถุ String ที่มีเนื้อหา "Hello" จากนั้นเราดำเนินการ + บน s วัตถุนั้นชี้ไปโดย s เปลี่ยนไปหรือไม่ คำตอบคือไม่ ในขณะนี้ s ไม่ได้ชี้ไปที่วัตถุต้นฉบับอีกต่อไป แต่ชี้ไปที่วัตถุ String อื่นที่มีเนื้อหา "Hello world!" วัตถุต้นฉบับยังคงอยู่ในหน่วยความจำ แต่ตัวแปรอ้างอิง s จะไม่ชี้ไปที่วัตถุนั้นอีกต่อไป
จากคำอธิบายข้างต้น เราสามารถหาข้อสรุปอื่นได้อย่างง่ายดาย หากสตริงถูกแก้ไขบ่อยครั้งด้วยวิธีต่างๆ หรือแก้ไขโดยไม่คาดคิด การใช้ String เพื่อแสดงสตริงจะทำให้หน่วยความจำโอเวอร์เฮดจำนวนมาก เนื่องจากอ็อบเจ็กต์ String ไม่สามารถเปลี่ยนแปลงได้หลังจากที่ถูกสร้างขึ้นแล้ว อ็อบเจ็กต์ String จึงจำเป็นต้องแสดงแต่ละสตริงที่แตกต่างกัน ในเวลานี้ คุณควรพิจารณาใช้คลาส StringBuffer ซึ่งอนุญาตให้แก้ไข แทนที่จะสร้างออบเจ็กต์ใหม่สำหรับแต่ละสตริงที่แตกต่างกัน นอกจากนี้ การเปลี่ยนแปลงนโยบายระหว่างสองประเภทนี้ทำได้ง่ายมาก
ในเวลาเดียวกัน เราทราบได้ด้วยว่าหากคุณต้องการใช้สตริงที่มีเนื้อหาเดียวกัน คุณไม่จำเป็นต้องสร้างสตริงใหม่ทุกครั้ง ตัวอย่างเช่น หากเราต้องการเริ่มต้นตัวแปรอ้างอิง String ชื่อ s ในตัวสร้างและตั้งค่าเป็นค่าเริ่มต้น เราควรดำเนินการดังนี้:
คัดลอกรหัสรหัสดังต่อไปนี้:
การสาธิตคลาสสาธารณะ {
สตริงส่วนตัว s;
-
การสาธิตสาธารณะ {
s = "ค่าเริ่มต้น";
-
-
-
แทนที่จะเป็น s = new String("ค่าเริ่มต้น");
อย่างหลังจะเรียก Constructor ทุกครั้งเพื่อสร้างอ็อบเจ็กต์ใหม่ ซึ่งมีประสิทธิภาพต่ำและใช้หน่วยความจำมาก และไม่มีความหมาย เนื่องจากอ็อบเจ็กต์ String ไม่สามารถเปลี่ยนแปลงได้ จึงสามารถใช้อ็อบเจ็กต์ String เดียวเท่านั้นเพื่อแสดงสตริงที่มีเนื้อหาเดียวกัน . กล่าวอีกนัยหนึ่ง หากคุณเรียก Constructor ข้างต้นหลายครั้งเพื่อสร้างหลายเป้าหมาย แอตทริบิวต์ประเภทสตริงจะชี้ไปที่เป้าหมายเดียวกัน
ข้อสรุปข้างต้นยังขึ้นอยู่กับข้อเท็จจริงที่ว่าสำหรับค่าคงที่สตริง หากเนื้อหาเหมือนกัน Guangzhou Java Training เชื่อว่าเนื้อหาเหล่านั้นแสดงถึงอ็อบเจ็กต์ String เดียวกัน การเรียก Constructor ด้วยคีย์เวิร์ด new จะสร้างเป้าหมายใหม่เสมอ ไม่ว่าเนื้อหาจะเหมือนกันหรือไม่ก็ตาม
สำหรับสาเหตุที่คลาส String ควรถูกอธิบายว่าเป็นคลาสที่ไม่เปลี่ยนรูปนั้นจะถูกกำหนดโดยวัตถุประสงค์ ในความเป็นจริง ไม่เพียงแต่ String เท่านั้น แต่ยังมีหลายคลาสในไลบรารีคลาสมาตรฐาน Java ที่ไม่เปลี่ยนรูปอีกด้วย เมื่อพัฒนาระบบ บางครั้งเราจำเป็นต้องอธิบายคลาสที่ไม่เปลี่ยนรูปเพื่อส่งผ่านชุดของค่านิยมที่เกี่ยวข้อง ซึ่งเป็นการแสดงออกถึงการคิดเชิงเป้าหมายด้วย คลาสที่ไม่เปลี่ยนรูปมีข้อดีบางประการ ตัวอย่างเช่น เนื่องจากวัตถุประสงค์เป็นแบบอ่านอย่างเดียว จึงไม่มีปัญหาในการเข้าถึงพร้อมกันหลายเธรด แน่นอนว่ายังมีข้อบกพร่องอยู่บ้าง ตัวอย่างเช่น แต่ละสถานการณ์จำเป็นต้องมีวัตถุเพื่อเป็นตัวแทน ซึ่งอาจทำให้เกิดปัญหาในการทำงานได้ ดังนั้นไลบรารีคลาสมาตรฐาน Java จึงจัดเตรียมเวอร์ชันตัวแปร ซึ่งก็คือ StringBuffer