ในสองบทความก่อนหน้านี้ เราได้พูดคุยถึงคำถามสำคัญบางข้อที่คุณมักถูกถามบ่อยที่สุดในการสัมภาษณ์ ถึงเวลาที่จะดำเนินการต่อและดูคำถามที่เหลือ
การคัดลอกแบบลึกและการคัดลอกแบบตื้น
สำเนาต้นฉบับที่ถูกต้องคือโคลนของมัน ใน Java นี่หมายถึงความสามารถในการสร้างวัตถุที่มีโครงสร้างคล้ายกับวัตถุดั้งเดิม วิธีการนี้clone()
มีฟังก์ชันการทำงานนี้ การคัดลอกแบบตื้นคัดลอกข้อมูลให้น้อยที่สุด ตามค่าเริ่มต้น การโคลนนิ่งใน Java เป็นแบบตื้น เช่น Object class
ไม่รู้เกี่ยวกับโครงสร้างของคลาสที่กำลังคัดลอก เมื่อทำการโคลน JVM จะดำเนินการดังต่อไปนี้:
- หากคลาสมีเพียงสมาชิกของประเภทดั้งเดิม สำเนาใหม่ของออบเจ็กต์จะถูกสร้างขึ้นและการอ้างอิงถึงออบเจ็กต์นั้นจะถูกส่งกลับ
- หากคลาสไม่เพียงมีสมาชิกของประเภทดั้งเดิมเท่านั้น แต่ยังรวมถึงสมาชิกของประเภทคลาสอื่นด้วย การอ้างอิงไปยังออบเจ็กต์ของคลาสเหล่านี้จะถูกคัดลอก ดังนั้นวัตถุทั้งสองจะมีการอ้างอิงที่เหมือนกัน
- ไม่จำเป็นต้องคัดลอกข้อมูลดั้งเดิมแยกกัน
- คลาสสมาชิกทั้งหมดในคลาสดั้งเดิมต้องรองรับการโคลนนิ่ง สำหรับสมาชิกคลาสแต่ละคน จะต้องถูกเรียก
super.clone()
เมื่อเมธอดถูกแทนที่clone()
; - หากสมาชิกของคลาสไม่รองรับการโคลน ดังนั้นในวิธีการโคลน คุณจะต้องสร้างอินสแตนซ์ใหม่ของคลาสนั้นและคัดลอกสมาชิกแต่ละคนพร้อมคุณสมบัติทั้งหมดไปยังอ็อบเจ็กต์คลาสใหม่ ทีละตัว
การซิงโครไนซ์คืออะไร? การล็อคระดับวัตถุและการล็อคระดับคลาส?
การซิงโครไนซ์หมายถึงมัลติเธรด บล็อกโค้ดที่ซิงโครไนซ์สามารถดำเนินการได้ครั้งละหนึ่งเธรดเท่านั้น Java ช่วยให้คุณสามารถประมวลผลหลายเธรดพร้อมกันได้ ซึ่งอาจส่งผลให้มีเธรดตั้งแต่สองเธรดขึ้นไปต้องการเข้าถึงฟิลด์เดียวกัน การซิงโครไนซ์ช่วยหลีกเลี่ยงข้อผิดพลาดของหน่วยความจำที่เกิดขึ้นเมื่อใช้ทรัพยากรหน่วยความจำอย่างไม่ถูกต้อง เมื่อมีการประกาศวิธีการซิงโครไนซ์ เธรดจะเก็บมอนิเตอร์ไว้ หากเธรดอื่นพยายามเข้าถึงวิธีการซิงโครไนซ์ในขณะนี้ เธรดนั้นจะถูกบล็อกและรอให้จอภาพว่าง การซิงโครไนซ์ใน Java ทำได้สำเร็จด้วยคีย์เวิร์ด ซิงโครไนซ์ พิเศษ คุณสามารถทำเครื่องหมายแต่ละบล็อกหรือวิธีการในชั้นเรียนของคุณได้ด้วยวิธีนี้ คำสำคัญที่ซิงโครไนซ์ไม่สามารถใช้ร่วมกับตัวแปรคลาสหรือคุณลักษณะได้ การล็อกระดับออบเจ็กต์เป็นกลไกเมื่อคุณต้องการซิงโครไนซ์วิธีการที่ไม่คงที่หรือบล็อกโค้ดที่ไม่คงที่เพื่อให้เธรดเดียวเท่านั้นที่สามารถดำเนินการบล็อกของโค้ดบนอินสแตนซ์ที่กำหนดของคลาสได้ สิ่งนี้ควรทำเสมอเพื่อทำให้เธรดอินสแตนซ์ของคลาสปลอดภัย การล็อกระดับคลาสจะป้องกันไม่ให้เธรดจำนวนมากเข้าสู่บล็อกที่ซิงโครไนซ์สำหรับอินสแตนซ์ที่มีอยู่ทั้งหมดของคลาส ตัวอย่างเช่น หากมี 100 อินสแตนซ์ของคลาส DemoClass จะมีเพียง 1 เธรดเท่านั้นที่จะสามารถดำเนินการ demoMethod() โดยใช้ตัวแปรตัวใดตัวหนึ่งในเวลาที่กำหนด สิ่งนี้ควรทำเสมอเพื่อความปลอดภัยของเธรดแบบคงที่ เรียนรู้เพิ่มเติมเกี่ยวกับการซิงโครไนซ์ที่นี่ความแตกต่างระหว่าง sleep() และ wait() คืออะไร?
Sleep()
เป็นวิธีการที่ใช้ในการชะลอกระบวนการไม่กี่วินาที ในกรณีของwait()
เธรดจะอยู่ในสถานะรอจนกว่าเราจะเรียกเมธอดnotify()
or notifyAll()
ข้อแตกต่างที่สำคัญคือwait()
จะปลดล็อคจอภาพในขณะที่sleep()
ไม่ได้ปลดล็อค Wait()
ใช้สำหรับแอปพลิเคชันแบบมัลติเธรดsleep()
ใช้เพื่อหยุดการทำงานของเธรดชั่วคราว Thread.sleep()
ทำให้เธรดปัจจุบันอยู่ในสถานะ "ไม่สามารถรันได้" เป็นระยะเวลาหนึ่ง เธรดจะบันทึกสถานะของจอภาพที่เคยเป็นก่อนที่จะเรียกเมธอดนี้ หากมีการเรียกเธรดอื่นt.interrupt()
เธรดที่ "หลับ" จะถูกปลุกขึ้นมา โปรดทราบว่านี่sleep()
เป็นวิธีคงที่ ซึ่งหมายความว่าจะส่งผลต่อเธรดปัจจุบันเสมอ (วิธีดำเนินการ method sleep()
) ข้อผิดพลาดทั่วไปคือการเรียกt.sleep()
Where t
is another thread; แม้ว่าเธรดปัจจุบันที่เรียกว่าเมธอดsleep()
จะไม่ใช่t
เธรดก็ตาม Object.wait()
ส่งเธรดปัจจุบันเข้าสู่สถานะ "Not Runnable" ชั่วขณะหนึ่ง เช่นเดียวกับsleep()
แต่มีความแตกต่างกันเล็กน้อย Wait()
เรียกบนวัตถุ ไม่ใช่เธรด เราเรียกวัตถุนี้ว่า "วัตถุล็อค" ก่อนที่จะโทรlock.wait()
เธรดปัจจุบันจะต้องซิงโครไนซ์กับ "วัตถุล็อค"; wait()
หลังจากนั้นจะปลดล็อกนี้ และเพิ่มเธรดลงใน "รายการรอ" ที่เกี่ยวข้องกับการล็อกนี้ ต่อมา เธรดอื่นสามารถซิงโครไนซ์กับอ็อบเจ็กต์ล็อคเดียวกันและเรียกใช้ไฟล์lock.notify()
. วิธีนี้จะ "ปลุก" เธรดเดิมที่ยังรออยู่ ตามหลักการแล้วwait()
/ notify()
สามารถเปรียบเทียบได้กับsleep()
/ interrupt()
เฉพาะเธรดที่ใช้งานอยู่เท่านั้นที่ไม่ต้องการตัวชี้โดยตรงไปยังเธรดที่กำลังหลับ เพียงแต่จำเป็นต้องรู้อ็อบเจ็กต์การล็อกที่แชร์เท่านั้น อ่านรายละเอียดความแตกต่างได้ที่นี่
เป็นไปได้ไหมที่จะกำหนดค่าว่างให้กับตัวแปรอ้างอิง?
ไม่คุณไม่สามารถ. ใน Java ทางด้านซ้ายของตัวดำเนินการกำหนดจะต้องเป็นตัวแปร "This" เป็นคีย์เวิร์ดพิเศษที่ให้อินสแตนซ์ปัจจุบันของคลาสเสมอ มันไม่ใช่แค่ตัวแปรใดๆ ในทำนองเดียวกัน ไม่สามารถกำหนด null ให้กับตัวแปรโดยใช้คีย์เวิร์ด "super" หรือคีย์เวิร์ดอื่นๆ ที่คล้ายกัน&& และ & && ต่างกันอย่างไร?
&
- ระดับบิตและ&&
- เชิงตรรกะ
&
ประเมินการดำเนินงานทั้งสองด้าน&&
ประเมินด้านซ้ายของการดำเนินการ หากเป็นจริงก็ประเมินฝั่งขวาต่อไป
จะแทนที่วิธีเท่ากับ () และ hachCode () ได้อย่างไร
hashCode()
และequals()
วิธีการถูกกำหนดไว้ในคลาสObject
ซึ่งเป็นคลาสพาเรนต์สำหรับอ็อบเจ็กต์ Java ด้วยเหตุนี้ ออบเจ็กต์ Java ทั้งหมดจึงสืบทอดการใช้งานเริ่มต้นสำหรับเมธอด วิธีการนี้hashCode()
ใช้เพื่อให้ได้จำนวนเต็มเฉพาะสำหรับวัตถุที่กำหนด จำนวนเต็มนี้ใช้เพื่อกำหนดตำแหน่งของวัตถุเมื่อจำเป็นต้องจัดเก็บวัตถุนั้นHashTable
เช่น ตามค่าเริ่มต้นhashCode()
ส่งคืนinteger
การแสดงที่อยู่ของตำแหน่งหน่วยความจำที่จัดเก็บออบเจ็กต์ วิธีการequls()
ตามชื่อของมัน ใช้เพื่อทดสอบว่าวัตถุสองชิ้นเท่ากันหรือไม่ การใช้งานเริ่มต้นจะตรวจสอบการอ้างอิงออบเจ็กต์เพื่อดูว่าเท่ากันหรือไม่ ด้านล่างนี้เป็นแนวทางที่สำคัญสำหรับการโหลดวิธีการเหล่านี้ซ้ำ:
- ใช้แอตทริบิวต์ของวัตถุเดียวกันเสมอเมื่อสร้าง
hashCode()
และequals()
; - สมมาตร. เหล่านั้น.
x
ถ้า มัน คืนค่าจริง สำหรับบางอ็อบเจ็กต์y
x.equals(y)
ก็y.equals(x)
ควรคืนค่าจริง - สะท้อนแสง สำหรับวัตถุใด ๆ
x
x.equals(x)
จะต้องคืนค่าจริง - ความสม่ำเสมอ สำหรับวัตถุใด ๆ
x
และy
x.equals(y)
ส่งกลับสิ่งเดียวกันหากข้อมูลที่ใช้ในการเปรียบเทียบไม่เปลี่ยนแปลง - การขนส่ง สำหรับอ็อบเจ็กต์ใดๆ
x
และถ้ามันคืนค่าจริงและส่งกลับค่าจริง ก็ ควรจะy
คืนค่าจริงz
x.equals(y)
y.equals(z)
x.equals(z)
- เมื่อใดก็ตามที่มีการเรียกใช้เมธอดบนออบเจ็กต์เดียวกันระหว่างการทำงานของแอปพลิเคชัน ก็ควรส่งคืนหมายเลขเดียวกัน เว้นแต่ว่าข้อมูลที่ใช้จะเปลี่ยนแปลง
hashCode
สามารถคืนค่าที่แตกต่างกันสำหรับวัตถุที่เหมือนกันในอินสแตนซ์ของแอปพลิเคชันที่แตกต่างกัน - หากวัตถุสองชิ้นมีค่าเท่ากัน ตามนั้น
equals
วัตถุทั้งสองhashCode
จะต้องส่งคืนค่าเดียวกัน - ข้อกำหนดตรงกันข้ามเป็นทางเลือก วัตถุสองวัตถุที่ไม่เท่ากันสามารถส่งคืน hashCode เดียวกันได้ อย่างไรก็ตาม เพื่อปรับปรุงประสิทธิภาพ ควรให้อ็อบเจ็กต์ที่แตกต่างกันส่งคืนโค้ดที่แตกต่างกันจะดีกว่า
บอกเราเกี่ยวกับตัวแก้ไขการเข้าถึง
คลาส Java, ฟิลด์, ตัวสร้าง และเมธอดสามารถมีหนึ่งในสี่ตัวดัดแปลงการเข้าถึงที่แตกต่างกัน: ไพรเวท หากเมธอดหรือตัวแปรถูกทำเครื่องหมายเป็นไพรเวท เฉพาะโค้ดภายในคลาสเดียวกันเท่านั้นที่สามารถเข้าถึงตัวแปร หรือเรียกเมธอดนั้นได้ โค้ดภายในคลาสย่อยไม่สามารถเข้าถึงตัวแปรหรือเมธอด และไม่สามารถเข้าถึงได้จากคลาสอื่น ตัวแก้ไขการเข้าถึงส่วนตัวมักใช้สำหรับตัวสร้าง วิธีการ และตัวแปร ค่าเริ่มต้น ตัวแก้ไขการเข้าถึงเริ่มต้นจะถูกประกาศหากไม่ได้ระบุตัวแก้ไขเลย ตัวแก้ไขนี้หมายความว่าการเข้าถึงฟิลด์ ตัวสร้าง และวิธีการของคลาสที่กำหนดสามารถรับได้โดยโค้ดภายในคลาสนั้นเอง โค้ดภายในคลาสในแพ็คเกจเดียวกัน คลาสย่อยไม่สามารถเข้าถึงเมธอดและตัวแปรสมาชิกของซูเปอร์คลาสได้ หากถูกประกาศเป็นค่าเริ่มต้นเว้นแต่คลาสย่อยจะอยู่ในแพ็คเกจเดียวกันกับซูเปอร์คลาส protected ตัวดัดแปลงที่ได้รับการป้องกันทำงานเหมือนกับdefaultยกเว้นว่าคลาสย่อยยังสามารถเข้าถึงเมธอดและตัวแปรที่ได้รับการป้องกันของซูเปอร์คลาสได้ คำสั่งนี้เป็นจริงแม้ว่าคลาสย่อยจะไม่ได้อยู่ในแพ็คเกจเดียวกันกับซูเปอร์คลาสก็ตาม public ตัวแก้ไขการเข้าถึงสาธารณะหมายความว่าโค้ดทั้งหมดสามารถเข้าถึงคลาส ตัวแปร ตัวสร้าง หรือเมธอดได้ โดยไม่คำนึงว่าโค้ดนั้นจะอยู่ที่ใด
คนเก็บขยะคืออะไร? เราโทรหาเขาได้ไหม?
Garbage Collection เป็นฟีเจอร์หนึ่งของการจัดการหน่วยความจำอัตโนมัติในภาษาโปรแกรมสมัยใหม่หลายๆ ภาษา เช่น Java และภาษาต่างๆ ใน NET.Framework ภาษาที่ใช้การรวบรวมขยะมักจะตีความการรวบรวมขยะในเครื่องเสมือนเช่น JVM การรวบรวมขยะมีวัตถุประสงค์สองประการ: หน่วยความจำที่ไม่ได้ใช้ควรถูกทำให้ว่าง และหน่วยความจำไม่ควรถูกทำให้ว่างหากโปรแกรมยังคงใช้งานอยู่ คุณสามารถเรียกใช้การรวบรวมขยะด้วยตนเองได้หรือไม่? ไม่System.gc()
มันช่วยให้คุณเข้าถึงได้มากที่สุดเท่าที่จะเป็นไปได้ ตัวเลือกที่ดีที่สุดคือการเรียกเมธอดSystem.gc()
ซึ่งจะบอกใบ้ให้ตัวรวบรวมขยะจำเป็นต้องเรียกใช้ ไม่มีวิธีรันทันทีเนื่องจากตัวรวบรวมขยะไม่สามารถกำหนดได้ นอกจากนี้ ตามเอกสารประกอบOutOfMemoryError
จะไม่มีการส่งต่อหากเครื่องเสมือนล้มเหลวในการเพิ่มหน่วยความจำหลังจากการรวบรวมขยะทั้งหมด เรียนรู้เพิ่มเติมเกี่ยวกับตัวเก็บขยะที่นี่
คำหลักพื้นเมืองหมายถึงอะไร? อธิบายอย่างละเอียด
คำหลักเนทิ ฟ ใช้เพื่อระบุว่ามีการใช้วิธีนี้ในภาษาการเขียนโปรแกรมอื่นที่ไม่ใช่ไฟล์ Java วิธีการ ดั้งเดิมถูกนำมาใช้ในอดีต ใน Java เวอร์ชันปัจจุบัน สิ่งนี้จำเป็นน้อยลง ปัจจุบันจำเป็นต้องใช้วิธีการดั้งเดิมเมื่อ:- คุณต้องเรียกไลบรารีจาก Java ที่เขียนในภาษาอื่น
- คุณต้องเข้าถึงทรัพยากรระบบหรือฮาร์ดแวร์ที่สามารถเข้าถึงได้โดยใช้ภาษาอื่นเท่านั้น (โดยปกติคือ C) ในความเป็นจริง ฟังก์ชันระบบหลายอย่างที่โต้ตอบกับคอมพิวเตอร์จริง (เช่น ดิสก์หรือข้อมูลเครือข่าย) สามารถเรียกได้โดยวิธีการดั้งเดิมเท่านั้น
- JNI/JNA อาจทำให้ JVM ไม่เสถียร โดยเฉพาะอย่างยิ่งหากคุณพยายามทำสิ่งที่ซับซ้อน หากวิธีดั้งเดิมของคุณทำสิ่งผิดปกติ มีความเป็นไปได้ที่ JVM จะขัดข้อง นอกจากนี้ สิ่งเลวร้ายอาจเกิดขึ้นได้หากวิธีดั้งเดิมของคุณถูกเรียกจากหลายเธรด และอื่นๆ
- การดีบัก โปรแกรมด้วยโค้ดเนทีฟ นั้นยากกว่า
- โค้ดแบบเนทีฟต้องมีการสร้างเฟรมเวิร์กแยกต่างหาก ซึ่งอาจทำให้เกิดปัญหาในการพอร์ตไปยังแพลตฟอร์มอื่นได้
การทำให้เป็นอนุกรมคืออะไร?
ในวิทยาการคอมพิวเตอร์ ในบริบทของการจัดเก็บและการส่งข้อมูล การทำให้เป็นอนุกรมเป็นกระบวนการแปลโครงสร้างข้อมูลหรือสถานะของออบเจ็กต์ให้อยู่ในรูปแบบที่สามารถจัดเก็บและเรียกค้นได้ในภายหลังในสภาพแวดล้อมการประมวลผลอื่น หลังจากได้รับชุดของบิตแล้ว บิตเหล่านั้นจะถูกคำนวณใหม่ตามรูปแบบการทำให้เป็นอนุกรม และสามารถใช้เพื่อสร้างโคลนที่เหมือนกันทางความหมายของออบเจ็กต์ต้นฉบับได้ Java จัดให้มีการทำให้เป็นอนุกรมอัตโนมัติ ซึ่งต้องใช้อ็อบเจ็กต์เพื่อใช้อินเทอร์เฟjava.io.Serializable
ซ การใช้งานอินเทอร์เฟซทำเครื่องหมายคลาสว่า "ต่อเนื่องได้" อินเทอร์เฟซ java.io.Serializable ไม่มีวิธีการทำให้เป็นอนุกรม แต่คลาสที่ทำให้เป็นอนุกรมสามารถเลือกกำหนดวิธีการที่จะเรียกว่าเป็นส่วนหนึ่งของกระบวนการทำให้เป็นอนุกรม/กระจายการซีเรียลไลซ์ได้ เมื่อทำการเปลี่ยนแปลงคลาส คุณต้องพิจารณาว่าคลาสใดจะเข้ากันได้กับซีเรียลไลซ์ คุณสามารถอ่านคำแนะนำแบบเต็มได้ที่นี่ ฉันจะให้คะแนนที่สำคัญที่สุด: การเปลี่ยนแปลงที่เข้ากันไม่ได้:
- ลบฟิลด์;
- ย้ายชั้นเรียนขึ้นหรือลงในลำดับชั้น
- การเปลี่ยนฟิลด์ที่ไม่คงที่เป็นแบบคงที่หรือแบบไม่ชั่วคราวเป็นชั่วคราว
- การเปลี่ยนชนิดข้อมูลดั้งเดิมที่ประกาศ
- การเปลี่ยนวิธีการเพื่อไม่ให้เขียนหรืออ่านฟิลด์ตามค่าเริ่มต้นอีกต่อ
WriteObject
ไปReadObject
- การเปลี่ยนชั้นเรียน
Serializable
เป็นExternalizable
หรือในทางกลับกัน - การเปลี่ยน คลาส enumเป็นnon-enumหรือในทางกลับกัน
- การถอด
Serializable
หรือExternalizable
; - การเพิ่ม
writeReplace
วิธี การให้readResolve
กับชั้นเรียน
- การเพิ่มฟิลด์;
- การเพิ่ม/ลบคลาส;
- การเพิ่มเมธอด
WriteObject/ReadObject
[วิธีการdefaultReadObject
หรือdefaultWriteObject
ต้องเรียกตอนต้น]; - วิธีการลบ
WriteObject/ReadObject
; - ส่วนที่เพิ่มเข้าไป
java.io.Serializable
; - การเปลี่ยนแปลงการเข้าถึงสนาม
- การเปลี่ยน ฟิลด์ สแตติกเป็นแบบไม่คงที่หรือชั่วคราวเป็นไม่ชั่วคราว
GO TO FULL VERSION