ร่าง 1. “วิธีการที่ดูเรียบง่าย”
เขียนว่าคุณจะใช้วิธีการส่งคืนผลลัพธ์ของการหารตัวเลข a ด้วยตัวเลข b อย่างไร ผู้สัมภาษณ์เขียนลงบนกระดาษint divide(int a, int b) {
}
*ฉันเหลือบมองกระดาษที่มีลายเซ็นวิธีการอย่างเหลือเชื่อ ที่จับคืออะไร * ฉันเขียน:
int divide(int a, int b) {
return a/b;
}
วิธีนี้มีปัญหาหรือไม่? *ฉันเจอคนโง่เขลาจริงๆ* เห็นได้ชัดว่าไม่ใช่.. ถัดมาเป็นคำถามที่ถูกต้อง: จะเกิดอะไรขึ้นถ้า b=0? *โอ้โห ฉันกำลังจะโดนไล่ออกจากออฟฟิศแล้วถ้ายังทำแบบนี้ต่อไป!* โอ้ ใช่ แน่นอน ที่นี่เรามีอาร์กิวเมนต์ประเภท int ดังนั้น Arithmetic Exception จะถูกส่งออกไป หากอาร์กิวเมนต์เป็นแบบ float หรือ double ผลลัพธ์จะเป็น Infinity เราจะทำอย่างไรเกี่ยวกับเรื่องนี้? ฉันเริ่มเขียน try/catch
int divide(int a, int b) {
try {
return a/b;
} catch (Exception e) {
e.printStackTrace();
return ... // ??? what the hack?
}
}
*ฉันสามารถคืนสินค้าและหยุดนิ่งได้: จำเป็นต้องคืนบางสิ่งในกรณีที่เกิดข้อผิดพลาด แต่ "บางสิ่ง" นี้แตกต่างจากผลการคำนวณได้อย่างไร * เราจะได้อะไรกลับมา? หืม... ฉันจะเปลี่ยนประเภทของตัวแปรส่งคืนเป็น Integer และในกรณีที่มีข้อยกเว้น ฉันจะคืนค่า null ลองจินตนาการว่าเราไม่สามารถเปลี่ยนประเภทได้ เราจะออกไปได้ไหม? บางทีเราอาจทำอย่างอื่นได้ยกเว้นข้อยกเว้น? *มาแล้ว* เราสามารถส่งต่อไปยังวิธีการโทรได้เช่นกัน! ขวา. มันจะมีลักษณะอย่างไร?
int divide(int a, int b) throws ArithmeticException{
return a/b;
}
void callDivide(int a, int b) {
try {
divide(a, b);
} catch (ArithmeticException e) {
e.printStackTrace();
}
}
จำเป็นต้องจัดการกับข้อยกเว้นหรือไม่? ใช่ เพราะเราส่งต่ออย่างชัดเจนจากวิธีหาร (*ฉันผิดที่นี่! ต่อไปนี้คือคำถามนำจากผู้สัมภาษณ์เพื่อให้ได้คำตอบที่ถูกต้อง*) และข้อยกเว้นทางคณิตศาสตร์ - มีข้อยกเว้นประเภทใด - เลือกหรือไม่เลือก? นี่เป็นข้อยกเว้นรันไทม์ ซึ่งหมายความว่าไม่ได้เลือก *คำถามยอดฮิตมาถึงแล้ว* ปรากฏว่าตามคำพูดของคุณ ถ้าเราระบุ Throws Arithmetic Exception ในลายเซ็นเมธอด มันจะกลายเป็นข้อยกเว้นที่ถูกตรวจสอบใช่หรือไม่ *ฮึ!* อาจจะ... ไม่ ใช่ มันหายไปแล้ว หากเราระบุการพ่น /unchecked ข้อยกเว้น/ ในลายเซ็น เราจะเตือนเพียงว่าวิธีการนี้สามารถส่งข้อยกเว้นได้ แต่ไม่จำเป็นต้องจัดการในวิธีการเรียก ที่แยกออก มีอะไรอีกที่เราสามารถทำได้เพื่อหลีกเลี่ยงข้อผิดพลาดหรือไม่? *หลังจากคิดอยู่สักพัก* ใช่ เรายังสามารถตรวจสอบได้ว่า (b==0) หรือไม่ และดำเนินการตามตรรกะบางอย่าง ขวา. ดังนั้นเราสามารถไปได้ 3 วิธี:
- ลอง/จับ
- พ่น - ส่งต่อไปยังวิธีการโทร
- การตรวจสอบข้อโต้แย้ง
divide
คุณคิดว่าวิธีไหนดีกว่ากัน? ฉันจะเลือกที่จะส่งต่อข้อยกเว้นไปยังวิธีการโทรเพราะ... ในวิธีการหารยังไม่ชัดเจนว่าจะประมวลผลข้อยกเว้นนี้อย่างไรและผลลัพธ์ประเภทใดint
ที่ส่งคืนในกรณีที่เกิดข้อผิดพลาด และในวิธีการเรียก ฉันจะใช้อาร์กิวเมนต์ b เพื่อตรวจสอบว่ามีค่าเท่ากับศูนย์หรือไม่ ดูเหมือนว่าคำตอบนี้จะทำให้ผู้ให้สัมภาษณ์พอใจ แต่บอกตามตรง ฉันไม่แน่ใจว่าคำตอบนี้จะไม่คลุมเครือ))
ร่าง 2. “ใครเร็วกว่ากัน”
หลังจากคำถามมาตรฐาน ArrayList แตกต่างจาก LinkedList อย่างไร มาถึงสิ่งนี้: จะเกิดอะไรขึ้นเร็วกว่า - การแทรกองค์ประกอบลงตรงกลางArrayList
หรือตรงLinkedList
กลาง *ที่นี่ฉันข้ามไป ฉันจำได้ว่าทุกที่ที่ฉันอ่านข้อความเช่น “ใช้LinkedList
เพื่อแทรกหรือลบองค์ประกอบที่อยู่ตรงกลางรายการ” ที่บ้านฉันตรวจสอบการบรรยายของ JavaRush อีกครั้ง มีวลีหนึ่ง: “ถ้าคุณจะแทรก (หรือลบ) องค์ประกอบหลายอย่างลงตรงกลางคอลเลกชัน คุณควรใช้LinkedList
. ในกรณีอื่นๆ ทั้งหมด - ArrayList
” ตอบอัตโนมัติ* จะเร็วขึ้นด้วยLinkedList
. กรุณาชี้แจงด้วย
- ในการแทรกองค์ประกอบที่อยู่ตรงกลาง
ArrayList
เราจะค้นหาองค์ประกอบในรายการในเวลาคงที่ จากนั้นคำนวณดัชนีขององค์ประกอบทางด้านขวาขององค์ประกอบที่ถูกแทรกใหม่ตามเวลาเชิงเส้น - สำหรับ
LinkedList
.. ก่อนอื่นเราจะไปถึงจุดกึ่งกลางของเวลาเชิงเส้น จากนั้นจึงแทรกองค์ประกอบในเวลาคงที่ โดยเปลี่ยนลิงก์สำหรับองค์ประกอบข้างเคียง
LinkedList
เร็วกว่านี้? ปรากฎว่าเมื่อเราแทรกเข้าไปในครึ่งแรกของรายการ ตัวอย่างเช่น หากคุณแทรกไว้ที่จุดเริ่มต้น คุณArrayList
จะต้องคำนวณดัชนีทั้งหมดใหม่จนถึงส่วนท้ายสุด แต่คุณLinkedList
จะต้องเปลี่ยนการอ้างอิงขององค์ประกอบแรกเท่านั้น คุณธรรม: อย่าเชื่อทุกสิ่งที่เขียนอย่างแท้จริง แม้แต่ใน JavaRush!)
ร่าง 3. “เราจะอยู่ที่ไหนถ้าไม่มีความเท่าเทียมและแฮชโค้ด!”
การสนทนาเกี่ยวกับความเท่าเทียมกันและแฮชโค้ดนั้นยาวมาก - จะแทนที่มันได้อย่างไร การใช้งานแบบใดที่จะเกิดขึ้นObject
สิ่งที่เกิดขึ้นภายใต้ประทุน เมื่อมีการแทรกองค์ประกอบเข้าไปHashMap
ใน ฯลฯ ฉันจะให้คะแนนที่น่าสนใจในความคิดของฉันเพียงบางส่วน* ลองนึกภาพว่าเราได้สร้างชั้นเรียนขึ้นมา
public class A {
int id;
public A(int id) {
this.id = id;
}
}
และ พวกเขาไม่ได้แทนที่equals
และ hashcode
อธิบายว่าจะเกิดอะไรขึ้นเมื่อมีการรันโค้ด
A a1 = new A(1);
A a2 = new A(1);
Map<A, String> hash = new HashMap<>();
hash.put(a1, "1");
hash.get(a2);
*เป็นเรื่องดีที่ก่อนการสัมภาษณ์ ฉันใช้เวลาสองสามวันโดยเฉพาะในการทำความเข้าใจอัลกอริธึมพื้นฐาน ความซับซ้อน และโครงสร้างข้อมูล ซึ่งช่วยได้มาก ขอบคุณ CS50!*
-
สร้างคลาส A สองอินสแตนซ์
-
เราสร้างแผนที่เปล่า ซึ่งตามค่าเริ่มต้นจะมีตะกร้า 16 ใบ คีย์คืออ็อบเจ็กต์ของคลาส A ซึ่งเมธอด
equals
และ จะไม่ถูกhashcode
แทนที่ -
วางไว้
a1
ในแผนที่ ในการดำเนินการนี้ อันดับแรกเราคำนวณแฮa1
ชแฮชจะเท่ากับอะไร?
ที่อยู่ของเซลล์ในหน่วยความจำคือการนำวิธีการจากคลาสไปใช้
Object
-
เราจะคำนวณดัชนีตะกร้าตามแฮช
เราจะคำนวณมันได้อย่างไร?
*ขออภัย ฉันไม่ได้ให้คำตอบที่ชัดเจนที่นี่ คุณมีตัวเลขที่ยาว - แฮชและมีที่เก็บข้อมูล 16 อัน - จะกำหนดดัชนีได้อย่างไรเพื่อให้วัตถุที่มีแฮชต่างกันกระจายเท่า ๆ กันทั่วทั้งที่เก็บข้อมูล ฉันจินตนาการได้ว่าดัชนีมีการคำนวณดังนี้:
int index = hash % buckets.length
ที่บ้านฉันเห็นว่าการใช้งานดั้งเดิมในซอร์สโค้ดแตกต่างออกไปเล็กน้อย:
static int indexFor(int h, int length) { return h & (length - 1); }
-
เราตรวจสอบว่าไม่มีการชนกันและใส่ a1
-
เรามาดูวิธีการกันดี
get
กว่า รับประกันว่าอินสแตนซ์ a1 และ a2 จะมีที่แตกต่างกันhash
(ที่อยู่ต่างกันในหน่วยความจำ) ดังนั้นเราจะไม่พบสิ่งใดสำหรับคีย์นี้จะเกิดอะไรขึ้นถ้าเรากำหนดมันใหม่เฉพาะ
hashcode
ในคลาส A และพยายามแทรกลงในแฮชแมปก่อนด้วยคีย์ a1 แล้วตามด้วย a2?ก่อนอื่นเราจะค้นหาตะกร้าที่ต้องการโดย
hashcode
- การดำเนินการนี้จะดำเนินการอย่างถูกต้อง ต่อไป เรามาเริ่มดูออบเจ็กต์Entry
ใน LinkedList ที่แนบมากับรถเข็นแล้วเปรียบเทียบคีย์equals
ด้วย เพราะequals
ไม่ได้ถูกแทนที่ ดังนั้นการใช้งานพื้นฐานจะถูกนำมาจากคลาสObject
- การเปรียบเทียบโดยการอ้างอิง รับประกันว่า a1 และ a2 จะมีลิงก์ที่แตกต่างกัน ดังนั้นเราจะ "พลาด" องค์ประกอบที่แทรก a1 และ a2 จะถูกวางไว้ใน LinkedList เป็นโหนดใหม่ข้อสรุปคืออะไร? เป็นไปได้ไหมที่จะใช้เป็นคีย์ใน
HashMap
วัตถุที่ไม่มีการแทนที่equalshashcode
?ไม่คุณไม่สามารถ.
ร่าง 4. “จงใจทำลายมันซะ!”
หลังจากคำถามเกี่ยวกับข้อผิดพลาดและข้อยกเว้น คำถามต่อไปนี้ตามมา: เขียนตัวอย่างง่ายๆ ที่ฟังก์ชันจะส่ง StackOverflow *จากนั้นฉันก็จำได้ว่าข้อผิดพลาดนี้รบกวนจิตใจฉันอย่างไรเมื่อฉันพยายามเขียนฟังก์ชันแบบเรียกซ้ำ* สิ่งนี้อาจเกิดขึ้นในกรณีของการเรียกซ้ำ หากระบุเงื่อนไขในการออกจากการเรียกซ้ำไม่ถูกต้อง *จากนั้นฉันก็เริ่มฉลาดขึ้นนิดหน่อย ในที่สุดผู้สัมภาษณ์ก็ช่วย ทุกอย่างกลายเป็นเรื่องเรียบง่าย*void sof() {
sof();
}
Error นี้แตกต่างกับ อย่างไรOutOfMemory
? *ฉันไม่ได้ตอบที่นี่ แต่ภายหลังฉันพบว่านี่เป็นคำถามเกี่ยวกับความรู้เกี่ยวStack
กับHeap
หน่วยความจำ Java (การเรียกและการอ้างอิงไปยังอ็อบเจ็กต์จะถูกเก็บไว้ใน Stack และอ็อบเจ็กต์เองก็ถูกเก็บไว้ในหน่วยความจำ Heap) ดังนั้น StackOverflow จะถูกโยนทิ้งไปเมื่อไม่มีพื้นที่ในStack
หน่วยความจำเหลือสำหรับการเรียกใช้เมธอดถัดไป และOutOfMemory
พื้นที่สำหรับวัตถุในHeap
หน่วยความจำหมด*
นี่คือช่วงเวลาจากการสัมภาษณ์ที่ฉันจำได้ ในที่สุดฉันก็ได้รับการยอมรับให้ฝึกงานดังนั้นฉันจึงมีเวลาฝึกอบรม 2.5 เดือนข้างหน้าและหากทุกอย่างเป็นไปด้วยดีจะได้งานในบริษัท) หากมีความสนใจฉันสามารถเขียนบทความอื่นได้ คราวนี้เล็กลงด้วย การวิเคราะห์ปัญหาง่ายๆ แต่เป็นตัวอย่างที่ฉันได้รับการสัมภาษณ์จากบริษัทอื่น นั่นคือทั้งหมดสำหรับฉัน ฉันหวังว่าบทความนี้จะช่วยให้ใครบางคนมีข้อมูลเชิงลึกหรือจัดระเบียบความรู้ของพวกเขา มีความสุขในการเรียนรู้ทุกคน!
GO TO FULL VERSION