CodeGym /จาวาบล็อก /สุ่ม /สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Dev...
John Squirrels
ระดับ
San Francisco

สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer ตอนที่ 11

เผยแพร่ในกลุ่ม
สวัสดี! แม้แต่เรือที่เร็วที่สุดก็ยังลอยอยู่เหนือคลื่นได้ หากไม่มีเส้นทาง หากคุณกำลังอ่านบทความนี้อยู่ตอนนี้ แสดงว่าคุณมีเป้าหมายอย่างแน่นอน สิ่งสำคัญคืออย่าออกนอกเส้นทาง แต่มุ่งสู่การเป็น Java Developer แทน วันนี้ฉันต้องการทบทวนคำถามสำหรับนักพัฒนา Java ต่อไปเพื่อช่วยเติมเต็มช่องว่างทางทฤษฎีของคุณ สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer  ตอนที่ 11 - 1

97. มีกฎใดบ้างที่นำมาใช้เมื่อแทนที่เท่ากับ()?

เมื่อแทนที่เมธอดเท่ากับ () คุณต้องปฏิบัติตามกฎต่อไปนี้:
  • การสะท้อนกลับ — สำหรับค่าใดๆx , x.equals(x)จะต้องคืนค่าจริง เสมอ (โดยที่x != null )

  • สมมาตร — สำหรับค่าใดๆ ที่xและy x.equals(y)จะต้องคืนค่าเป็นจริงก็ต่อเมื่อy.equals(x)ส่งคืนค่าจริงเท่านั้น

  • การผ่านผ่าน — สำหรับค่าใดๆx , yและzถ้าx.equals(y)ส่งคืนtrueและy.equals(z)ส่ง คืน trueด้วยดังนั้นx.equals(z)จะต้องส่งคืนtrue

  • ความสอดคล้อง — สำหรับค่าใดๆxและyการเรียกx.equals(y) ซ้ำ ๆ จะส่งกลับค่าเดียวกันเสมอตราบใดที่ฟิลด์ที่ใช้ในการเปรียบเทียบวัตถุทั้งสองไม่มีการเปลี่ยนแปลงระหว่างการโทรแต่ละครั้ง

  • การเปรียบเทียบค่าว่าง — สำหรับค่าใดๆx การเรียกx.equals(null)จะต้องส่งคืนfalse

98. จะเกิดอะไรขึ้นถ้าคุณไม่แทนที่เท่ากับ() และ hashCode()?

ในกรณีนี้ hashCode() จะส่งคืนตัวเลขที่สร้างขึ้นตามที่อยู่ของเซลล์หน่วยความจำที่จัดเก็บวัตถุนั้น กล่าวอีกนัยหนึ่ง เมื่อ เรียกใช้ เมธอด hashCode() ดั้งเดิม บนอ็อบเจ็กต์สองตัวที่มีฟิลด์เดียวกัน ผลลัพธ์จะแตกต่างออกไป (เนื่องจากพวกมันถูกจัดเก็บไว้ในตำแหน่งหน่วยความจำต่างกัน) วิธีการ เท่ากับ ()ดั้งเดิมจะเปรียบเทียบการอ้างอิง กล่าวคือ เป็นการระบุว่าการอ้างอิงนั้นชี้ไปที่วัตถุเดียวกันหรือไม่ กล่าวอีกนัยหนึ่ง การเปรียบเทียบใช้ ตัวดำเนินการ ==และจะส่งคืนค่าเท็จสำหรับออบเจ็กต์ที่แตกต่างกันเสมอ แม้ว่าฟิลด์จะเหมือนกันก็ตาม trueจะถูกส่งกลับเฉพาะเมื่อเปรียบเทียบการอ้างอิงกับวัตถุเดียวกัน บางครั้งมันก็สมเหตุสมผลที่จะไม่แทนที่วิธีการเหล่านี้ ตัวอย่างเช่น คุณต้องการให้ออบเจ็กต์ทั้งหมดของคลาสใดคลาสหนึ่งไม่ซ้ำกัน การแทนที่วิธีการเหล่านี้อาจทำให้การรับประกันรหัสแฮชเฉพาะที่มีอยู่เสียหายเท่านั้น สิ่งสำคัญคือการเข้าใจความแตกต่างของวิธีการเหล่านี้ ไม่ว่าจะถูกแทนที่หรือไม่ก็ตาม และใช้วิธีการใดก็ตามที่สถานการณ์ต้องการ

99. เหตุใดข้อกำหนดด้านสมมาตรจึงเป็นไปตามข้อกำหนดเฉพาะในกรณีที่ x.equals(y) ส่งคืนค่าจริงเท่านั้น

คำถามนี้ค่อนข้างแปลก ถ้าวัตถุ A เท่ากับวัตถุ B แล้ววัตถุ B ก็เท่ากับวัตถุ A ถ้า B ไม่เท่ากับวัตถุ A แล้วสิ่งที่ตรงกันข้ามจะเป็นไปได้อย่างไร? นี่คือสามัญสำนึก

100. การชนกันของ HashCode คืออะไร? คุณจะจัดการกับมันอย่างไร?

การชนกัน ของ HashCodeเกิดขึ้นเมื่อวัตถุสองชิ้นที่แตกต่างกันมีHashCode เหมือน กัน เป็นไปได้อย่างไร? รหัสแฮชจะถูกแมปกับจำนวนเต็มซึ่งมีช่วงตั้งแต่ -2147483648 ถึง 2147483647 นั่นก็คือ มันสามารถเป็นหนึ่งในจำนวนเต็มที่แตกต่างกันประมาณ 4 พันล้านจำนวน ช่วงนี้มีขนาดใหญ่แต่ไม่สิ้นสุด นั่นหมายความว่ามีสถานการณ์ที่วัตถุสองชิ้นที่แตกต่างกันโดยสิ้นเชิงอาจมีรหัสแฮชเดียวกัน มันไม่น่าเป็นไปได้อย่างมาก แต่ก็เป็นไปได้ ฟังก์ชันแฮชที่ใช้งานไม่ดีสามารถทำให้รหัสแฮชที่เหมือนกันบ่อยขึ้นโดยการส่งคืนตัวเลขในช่วงเล็กๆ ซึ่งจะเป็นการเพิ่มโอกาสที่จะเกิดการชนกัน เพื่อลดการชนกัน คุณต้องมีการนำ เมธอด HashCode ไปใช้อย่างดี ซึ่งจะกระจายค่าอย่างสม่ำเสมอ และลดโอกาสที่จะเกิดค่าซ้ำ

101. จะเกิดอะไรขึ้นหากมูลค่าขององค์ประกอบที่เข้าร่วมในสัญญา hashCode เปลี่ยนแปลง?

หากองค์ประกอบที่เกี่ยวข้องกับการคำนวณรหัสแฮชเปลี่ยนแปลง รหัสแฮชของออบเจ็กต์ก็ควรเปลี่ยน (หากฟังก์ชันแฮชดี) นั่นเป็นเหตุผลที่คุณควรใช้วัตถุที่ไม่เปลี่ยนรูปเป็นคีย์ในHashMapเนื่องจากสถานะภายใน (ฟิลด์) ไม่สามารถเปลี่ยนแปลงได้หลังจากการสร้าง และตามมาด้วยว่ารหัสแฮชของพวกเขาเปลี่ยนไปหลังจากการสร้าง หากคุณใช้ออบเจ็กต์ที่ไม่แน่นอนเป็นคีย์ เมื่อฟิลด์ของออบเจ็กต์เปลี่ยนแปลง รหัสแฮชของมันจะเปลี่ยนไป และคุณอาจสูญเสียคู่คีย์-ค่าที่เกี่ยวข้องในHashMap ท้ายที่สุดแล้ว มันจะถูกจัดเก็บไว้ในที่เก็บข้อมูลที่เกี่ยวข้องกับรหัสแฮชดั้งเดิม แต่หลังจากการเปลี่ยนแปลงออบเจ็กต์ คุณจะค้นหามันในที่เก็บข้อมูลอื่น

102. เขียนเมธอดเท่ากับ() และ hashCode() สำหรับคลาส Student ที่มีฟิลด์ String name และ int age

public class Student {
int age;
String name;

 @Override
 public boolean equals(final Object o) {
   if (this == o) {
     return true;
   }
   if (o == null || this.getClass() != o.getClass()) {
     return false;
   }

   final Student student = (Student) o;

   if (this.age != student.age) {
     return false;
   }
   return this.name != null ? this.name.equals(student.name) : student.name == null;
 }

 @Override
 public int hashCode() {
   int result = this.age;
   result = 31 * result + (this.name != null ? this.name.hashCode() : 0);
   return result;
 }
}
เท่ากับ ():
  • อันดับแรก เราเปรียบเทียบข้อมูลอ้างอิงโดยตรง เพราะถ้าข้อมูลอ้างอิงชี้ไปที่วัตถุเดียวกัน จะมีประโยชน์อะไรในการตรวจสอบความเท่าเทียมกันต่อไป? เรารู้อยู่แล้วว่าผลลัพธ์จะเป็นจริง

  • เราตรวจสอบค่า null และประเภทคลาสเหมือนกันหรือไม่ เนื่องจากหากพารามิเตอร์เป็น null หรือประเภท อื่นออบเจ็กต์จะไม่เท่ากัน และผลลัพธ์จะต้องเป็นfalse

  • เราแปลงพารามิเตอร์เป็นประเภทเดียวกัน (ท้ายที่สุดแล้วหากเป็นออบเจ็กต์ประเภทพาเรนต์)

  • เราเปรียบเทียบฟิลด์ดั้งเดิม (การเปรียบเทียบโดยใช้=!ก็เพียงพอแล้ว) หากไม่เท่ากัน เราจะคืนค่าfalse

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

hashCode() :
  • เราตั้งค่าเริ่มต้นของรหัสแฮชให้เท่ากับค่าของฟิลด์อายุ ของวัตถุ

  • เราคูณรหัสแฮชปัจจุบันด้วย 31 (เพื่อค่าสเปรดที่มากขึ้น) จากนั้นเพิ่มรหัสแฮชของฟิลด์สตริงที่ไม่ใช่แบบดั้งเดิม (หากไม่เป็นค่าว่าง)

  • เราคืนผลลัพธ์

  • การเอาชนะวิธีการด้วยวิธีนี้หมายความว่าวัตถุที่มีชื่อและ ค่า int เหมือนกัน จะส่งคืนรหัสแฮชเดียวกันเสมอ

103. อะไรคือความแตกต่างระหว่างการใช้ "if (obj instanceof Student)" และ "if (getClass() == obj.getClass())"?

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

  • "getClass() == ..." ตรวจสอบว่าประเภทเหมือนกันหรือไม่

กล่าวอีกนัยหนึ่งgetClass()ส่งคืนเอกลักษณ์เฉพาะของคลาส แต่instanceofส่งคืนtrueแม้ว่าอ็อบเจ็กต์จะเป็นเพียงชนิดย่อย ซึ่งสามารถทำให้เรามีความยืดหยุ่นมากขึ้นเมื่อใช้ polymorphism ทั้งสองแนวทางมีแนวโน้มที่ดีหากคุณเข้าใจวิธีการทำงานอย่างแม่นยำและนำไปใช้ในตำแหน่งที่ถูกต้อง

104. ให้คำอธิบายสั้น ๆ เกี่ยวกับเมธอด clone()

วิธี การ clone()อยู่ในคลาสObject จุดประสงค์คือเพื่อสร้างและส่งคืนโคลน (สำเนา) ของออบเจ็กต์ปัจจุบัน สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer  ตอนที่ 11 - 2หากต้องการใช้วิธีนี้ คุณต้องใช้ อินเทอร์เฟซ Cloneable marker:
Student implements Cloneable
และแทนที่เมธอดclone()เอง:
@Override
protected Object clone() throws CloneNotSupportedException {
 return super.clone();
}
ท้ายที่สุด มันถูกป้องกันใน คลาส Objectกล่าวคือ จะมองเห็นได้เฉพาะใน คลาส Student เท่านั้น และคลาสภายนอกจะไม่สามารถมองเห็นได้

105. คุณต้องคำนึงถึงข้อควรพิจารณาพิเศษใดบ้างเกี่ยวกับเมธอด clone() และตัวแปรอ้างอิงในออบเจ็กต์?

เมื่อโคลนวัตถุ เฉพาะค่าดั้งเดิมและค่าของการอ้างอิงวัตถุเท่านั้นที่จะถูกคัดลอก ซึ่งหมายความว่าหากวัตถุมีช่องที่อ้างอิงถึงวัตถุอื่น เฉพาะการอ้างอิงเท่านั้นที่จะถูกโคลน - วัตถุที่อ้างอิงอื่นนี้จะไม่ถูกโคลน นี่คือสิ่งที่เรียกว่าสำเนาตื้น แล้วถ้าคุณต้องการสำเนาแบบเต็ม โดยที่ทุกอ็อบเจ็กต์ที่ซ้อนกันจะถูกโคลนล่ะ? คุณจะแน่ใจได้อย่างไรว่าสิ่งเหล่านี้ไม่ได้เป็นเพียงสำเนาของการอ้างอิง แต่เป็นสำเนาที่สมบูรณ์ของอ็อบเจ็กต์ที่แตกต่างซึ่งครอบครองที่อยู่หน่วยความจำที่แตกต่างกันในฮีป จริงๆ แล้ว ทุกอย่างค่อนข้างง่าย — สำหรับแต่ละคลาสที่มีการอ้างอิงภายใน คุณจะต้องแทนที่เมธอดclone()และเพิ่ม อินเทอร์เฟซ Cloneable marker เมื่อคุณทำเช่นนี้ การดำเนินการโคลนจะไม่คัดลอกการอ้างอิงไปยังออบเจ็กต์ที่มีอยู่ แต่จะคัดลอกออบเจ็กต์ที่อ้างอิงแทน เนื่องจากตอนนี้มีความสามารถในการคัดลอกด้วยตนเองแล้ว

ข้อยกเว้น

106. อะไรคือความแตกต่างระหว่างข้อผิดพลาดและข้อยกเว้น?

ข้อยกเว้น เช่นเดียวกับข้อผิดพลาด เป็นคลาสย่อยของThrowable อย่างไรก็ตามพวกเขามีความแตกต่างกัน ข้อผิดพลาดบ่งชี้ถึงปัญหาที่เกิดขึ้นส่วนใหญ่เนื่องจากการขาดแคลนทรัพยากรระบบ และแอปพลิเคชันของเราไม่ควรพบปัญหาประเภทนี้ ตัวอย่างของข้อผิดพลาดเหล่านี้ ได้แก่ ระบบล่มและข้อผิดพลาดหน่วยความจำไม่เพียงพอ ข้อผิดพลาดส่วนใหญ่เกิดขึ้นที่รันไทม์ เนื่องจากไม่ได้ทำเครื่องหมายไว้ สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer  ตอนที่ 11 - 3ข้อยกเว้นคือปัญหาที่อาจเกิดขึ้นขณะรันไทม์และขณะคอมไพล์ ปัญหาเหล่านี้มักเกิดขึ้นในโค้ดที่เราเขียนในฐานะนักพัฒนา นั่นหมายความว่าข้อยกเว้นเหล่านี้คาดเดาได้ง่ายกว่าและขึ้นอยู่กับเรามากกว่า ในทางตรงกันข้าม ข้อผิดพลาดจะเกิดขึ้นแบบสุ่มมากกว่าและเป็นอิสระจากเรามากกว่า แต่จะขึ้นอยู่กับปัญหาในระบบที่แอปพลิเคชันของเราทำงานอยู่แทน

107. อะไรคือความแตกต่างระหว่างการตรวจสอบ, ไม่ได้ตรวจสอบ, ข้อยกเว้น, การโยนและการโยน?

อย่างที่ผมได้กล่าวไว้ก่อนหน้านี้ข้อยกเว้นคือข้อผิดพลาดรันไทม์หรือเวลาคอมไพล์ที่เกิดขึ้นในโค้ดที่เขียนโดยนักพัฒนา (เนื่องจากสถานการณ์ที่ผิดปกติบางอย่าง) การตรวจสอบคือสิ่งที่เราเรียกว่าข้อยกเว้นที่วิธีการจะต้องจัดการโดยใช้ กลไก try-catch เสมอหรือสร้างใหม่เป็นวิธีการเรียก คำ สำคัญ พ่นใช้ในส่วนหัวของวิธีการเพื่อระบุข้อยกเว้นที่วิธีการอาจโยน กล่าวอีกนัยหนึ่ง มันทำให้เรามีกลไกในการส่งข้อยกเว้นไปยังวิธีการโทร ไม่จำเป็นต้องจัดการข้อยกเว้นที่ไม่ได้ ตรวจสอบ มีแนวโน้มที่จะคาดเดาได้น้อยกว่าและมีโอกาสน้อย ที่กล่าวว่าคุณสามารถจัดการได้ถ้าคุณต้องการ เราใช้การโยนเมื่อทำการโยนข้อยกเว้นด้วยตนเอง ตัวอย่างเช่น:
throw new Exception();

108. ลำดับชั้นข้อยกเว้นคืออะไร?

ลำดับชั้นของข้อยกเว้นนั้นกว้างขวางมาก มีมากเกินไปที่จะอธิบายได้อย่างเพียงพอที่นี่ ดังนั้น เราจะพิจารณาเฉพาะสาขาหลักแทน: สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer  ตอนที่ 11 - 4 ที่นี่ ที่ด้านบนสุดของลำดับชั้น เราจะเห็น คลาส Throwableซึ่งเป็นบรรพบุรุษทั่วไปของลำดับชั้นข้อยกเว้น และแบ่งออกเป็น:
  • ข้อผิดพลาด — ปัญหาร้ายแรงและไม่ถูกตรวจสอบ
  • ข้อยกเว้น — ข้อยกเว้นที่สามารถตรวจสอบได้
ข้อยกเว้นแบ่งออกเป็นข้อยกเว้นรันไทม์ที่ไม่ได้ตรวจสอบต่างๆ และข้อยกเว้นที่ได้รับการตรวจสอบต่างๆ

109. อะไรคือข้อยกเว้นที่ถูกตรวจสอบและไม่ถูกตรวจสอบ?

อย่างที่ฉันพูดไปก่อนหน้านี้:
  • ข้อยกเว้น ที่ตรวจสอบแล้วคือข้อยกเว้นที่คุณต้องจัดการด้วยวิธีใดวิธีหนึ่ง นั่นคือคุณต้องจัดการพวกมันใน บล็อก try-catchหรือโยนมันไปที่วิธีการด้านบน เมื่อต้องการทำเช่นนี้ หลังจากแสดงรายการอาร์กิวเมนต์ของวิธีการในลายเซ็นของวิธีการแล้ว ให้ใช้การส่ง <ประเภทข้อยกเว้น>เพื่อระบุว่าวิธีการดังกล่าวสามารถส่งข้อยกเว้นนั้นได้ นี่เป็นเหมือนคำเตือน โดยกำหนดให้วิธีการโทรแจ้งให้ทราบว่าจะต้องรับผิดชอบในการจัดการข้อยกเว้นนั้น

  • ไม่จำเป็นต้องจัดการข้อยกเว้นที่ไม่ได้ ตรวจสอบ เนื่องจากไม่ได้ตรวจสอบ ณ เวลาคอมไพล์ และมักจะคาดเดาไม่ได้มากกว่า ความแตกต่างหลักกับข้อยกเว้นที่ตรวจสอบแล้วคือการจัดการโดยใช้ บล็อก try-catchหรือโดยการโยนใหม่เป็นทางเลือกมากกว่าการบังคับ

101. เขียนตัวอย่างที่คุณใช้ try-catch block เพื่อตรวจจับและจัดการกับข้อยกเว้น

try{                                                 // Start of the try-catch block
 throw new Exception();                             // Manually throw an exception
} catch (Exception e) {                              // Exceptions of this type and its subtypes will be caught
 System.out.println("Oops! Something went wrong =("); // Display the exception
}

102. เขียนตัวอย่างที่คุณจับและจัดการกับข้อยกเว้นที่คุณกำหนดเอง

ขั้นแรก เรามาเขียนคลาสยกเว้นของเราเองที่สืบทอดExceptionและแทนที่ตัวสร้างที่รับข้อความแสดงข้อผิดพลาดเป็นอาร์กิวเมนต์:
public class CustomException extends Exception {

 public CustomException(final String message) {
   super(message);
 }
}
ต่อไป เราจะโยนมันด้วยตัวเองและจับมันเหมือนกับที่เราทำในตัวอย่างสำหรับคำถามก่อนหน้า:
try{
 throw new CustomException("Oops! Something went wrong =(");
} catch (CustomException e) {
 System.out.println(e.getMessage());
}
อีกครั้งหนึ่งเมื่อเรารันโค้ด เราจะได้ผลลัพธ์ดังต่อไปนี้:
อ๊ะ! มีบางอย่างผิดพลาด =(
สำรวจคำถามและคำตอบจากการสัมภาษณ์งานสำหรับตำแหน่ง Java Developer  ตอนที่ 11 - 5นั่นคือทั้งหมดสำหรับวันนี้! เจอกันใหม่ตอนหน้าครับ!
อ่านเพิ่มเติม:
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION