เนื้อหาต่อไปนี้เป็นคำถามและคำตอบที่รับผิดชอบหลังจากชุดคำถามสัมภาษณ์ Java ดั้งเดิมและคำตอบได้รับการแก้ไขอย่างสมบูรณ์ มีคำถามที่ซ้ำกันมากมายและคำถามที่มีค่าในคำถามดั้งเดิมและคำตอบอ้างอิงจำนวนมากก็ผิดเช่นกัน ชุดคำถามสัมภาษณ์ Java ที่แก้ไขแล้วอ้างอิงถึงเวอร์ชันล่าสุดของ JDK ลบเนื้อหาที่ไร้ประโยชน์เช่น EJB 2.x และเสริมโครงสร้างข้อมูลและคำถามที่เกี่ยวข้องกับอัลกอริทึมคำถามการเขียนโปรแกรมสัมภาษณ์แบบคลาสสิกสถาปัตยกรรมทางเทคนิคของเว็บไซต์ขนาดใหญ่ระบบปฏิบัติการฐานข้อมูลการทดสอบซอฟต์แวร์รูปแบบการออกแบบ ในเวลาเดียวกันมีการวิเคราะห์จุดรู้หลายจุดในเชิงลึกเช่นการออกแบบวิธีการ HashCode, กองและการสร้างการรวบรวมขยะ, การเขียนโปรแกรมใหม่พร้อมกันของ Java, Nio.2, ฯลฯ ฉันเชื่อว่ามันจะเป็นประโยชน์ต่อโปรแกรมเมอร์ Java ที่กำลังเตรียมเข้าร่วม
ชุดคำถามสัมภาษณ์โปรแกรมเมอร์ Java (1-50)
1. จาวาพื้นฐาน
1. ลักษณะของลักษณะเชิงวัตถุคืออะไร?
คำตอบ: ประเด็นหลักของคุณสมบัติเชิงวัตถุคือ:
1) บทคัดย่อ: นามธรรมเป็นกระบวนการสรุปลักษณะทั่วไปของประเภทของวัตถุในคลาสของวัตถุรวมถึงข้อมูลที่เป็นนามธรรมและพฤติกรรมที่เป็นนามธรรม สิ่งที่เป็นนามธรรมมุ่งเน้นเฉพาะคุณลักษณะและพฤติกรรมที่วัตถุมีและไม่ได้ใส่ใจกับรายละเอียดของพฤติกรรมเหล่านี้
2) การสืบทอด: การสืบทอดเป็นกระบวนการของการได้รับข้อมูลการสืบทอดจากคลาสที่มีอยู่และการสร้างคลาสใหม่ คลาสที่ให้ข้อมูลที่สืบทอดมานั้นเรียกว่าคลาสแม่ (SuperClass, คลาสฐาน); คลาสที่ได้รับข้อมูลที่สืบทอดมานั้นเรียกว่าคลาสย่อย (คลาสที่ได้รับ) การสืบทอดให้ระบบซอฟต์แวร์ที่เปลี่ยนแปลงมีระดับความต่อเนื่องและการสืบทอดก็เป็นวิธีที่สำคัญในการห่อหุ้มปัจจัยตัวแปรในโปรแกรม (หากคุณไม่เข้าใจโปรดอ่านส่วนเกี่ยวกับโหมดบริดจ์ใน "Java and Patterns" หรือ "รูปแบบการออกแบบที่ยอดเยี่ยม")
3) การห่อหุ้ม: โดยทั่วไปเชื่อว่าการห่อหุ้มคือการผูกข้อมูลกับวิธีการใช้งานข้อมูลและการเข้าถึงข้อมูลสามารถทำได้ผ่านอินเตอร์เฟสที่กำหนดไว้เท่านั้น สาระสำคัญของวัตถุที่มุ่งเน้นคือการพรรณนาโลกแห่งความเป็นจริงเป็นชุดของวัตถุอิสระและปิดอย่างสมบูรณ์ วิธีที่เราเขียนในชั้นเรียนคือการห่อหุ้มรายละเอียดการใช้งาน เราเขียนคลาสคือการห่อหุ้มข้อมูลและการดำเนินการข้อมูล อาจกล่าวได้ว่าบรรจุภัณฑ์คือการซ่อนทุกสิ่งที่สามารถซ่อนได้และให้เฉพาะอินเทอร์เฟซการเขียนโปรแกรมที่ง่ายที่สุดไปยังโลกภายนอก (คุณสามารถคิดถึงความแตกต่างระหว่างเครื่องซักผ้าธรรมดาและเครื่องซักผ้าอัตโนมัติอย่างสมบูรณ์เป็นที่ชัดเจนว่าเครื่องซักผ้าอัตโนมัติเต็มรูปแบบ
4) polymorphism: polymorphism หมายถึงการอนุญาตให้วัตถุของชนิดย่อยที่แตกต่างกันตอบสนองแตกต่างกันไปตามข้อความเดียวกัน พูดง่ายๆคือการเรียกวิธีการเดียวกันด้วยการอ้างอิงวัตถุเดียวกัน แต่ทำสิ่งต่าง ๆ ความหลากหลายถูกแบ่งออกเป็นความหลากหลายแบบคอมไพล์-เวลาและความหลากหลายในระยะเวลา หากวิธีการของวัตถุได้รับการยกย่องว่าเป็นบริการที่จัดทำโดยวัตถุไปสู่โลกภายนอกความหลากหลายของรันไทม์สามารถอธิบายได้ว่า: เมื่อระบบการเข้าถึงบริการที่จัดทำโดยระบบ B ระบบ B มีหลายวิธีในการให้บริการ วัตถุ แต่ไม่ทราบว่าการใช้งานระบบแหล่งจ่ายไฟเป็นอย่างไรและได้รับพลังงานอย่างไร) วิธีการที่โอเวอร์โหลดใช้การรวบรวมความหลากหลายเวลา (หรือที่เรียกว่า prebinding) ในขณะที่วิธีการแทนที่ใช้ polymorphism run-time (หรือที่เรียกว่า postbinding) ความหลากหลายของรันไทม์เป็นสิ่งที่สำคัญที่สุดเกี่ยวกับการมุ่งเน้นวัตถุ ในการใช้ polymorphism จำเป็นต้องทำสองสิ่ง: 1. วิธีการเขียนใหม่ (subclass สืบทอดคลาสพาเรนต์และเขียนวิธีที่มีอยู่หรือเป็นนามธรรมในคลาสหลัก); 2. การสร้างแบบจำลองวัตถุ (หมายถึงวัตถุประเภทลูกที่มีการอ้างอิงประเภทพาเรนต์เพื่อให้การอ้างอิงแบบเดียวกันนี้มีวิธีการเดียวกันจะแสดงพฤติกรรมที่แตกต่างกันตามวัตถุ subclass ที่แตกต่างกัน)
2. อะไรคือความแตกต่างระหว่างการเข้าถึงตัวดัดแปลงสาธารณะส่วนตัวการป้องกันและไม่เขียน (เริ่มต้น)?
คำตอบ: ความแตกต่างมีดังนี้:
ขอบเขตเหมือนกับ Subclass BUN
สาธารณะ√√√√√√√เมื่อใด
ได้รับการป้องกัน√√√√×
ค่าเริ่มต้น√√××
ส่วนตัว√×××
ค่าเริ่มต้นเป็นค่าเริ่มต้นเมื่อสมาชิกในชั้นเรียนไม่ได้เขียนการปรับเปลี่ยนการเข้าถึง โดยค่าเริ่มต้นมันจะเทียบเท่ากับสาธารณะสำหรับคลาสอื่น ๆ ในแพ็คเกจเดียวกันและส่วนตัวสำหรับคลาสอื่น ๆ ที่ไม่ได้อยู่ในแพ็คเกจเดียวกัน การป้องกันนั้นเทียบเท่ากับสาธารณะกับคลาสย่อยและส่วนตัวกับชั้นเรียนที่ไม่ได้อยู่ในแพ็คเกจเดียวกันที่ไม่มีความสัมพันธ์ระหว่างพ่อแม่และลูก
3. สตริงเป็นประเภทข้อมูลพื้นฐานที่สุดหรือไม่?
คำตอบ: ไม่ได้มีเพียง 8 ประเภทข้อมูลพื้นฐานใน Java: BYTE, Short, Int, Long, Float, Double, Char และ Boolean; ยกเว้นประเภทพื้นฐาน (ประเภทดั้งเดิม) และประเภทการแจงนับ (ประเภทการแจงนับ) ส่วนที่เหลือคือประเภทอ้างอิง (ประเภทอ้างอิง)
4. ลอย f = 3.4; ถูกต้องหรือไม่?
คำตอบ: ไม่ถูกต้อง 3.4 เป็นหมายเลขความแม่นยำสองเท่า การกำหนดประเภทจุดลอยตัว (ลอย) สองครั้ง (ลอย) จะทำให้เกิดการสูญเสียอย่างแม่นยำ (การหล่อลงหรือเรียกว่าการแคบ) ดังนั้นคุณต้องโยน Float F = (ลอย) 3.4; หรือเขียน float f = 3.4f;
5. สั้น S1 = 1; S1 = S1 + 1; มีอะไรผิดปกติหรือไม่? สั้น S1 = 1; S1 += 1; มีอะไรผิดปกติหรือไม่?
คำตอบ: สำหรับสั้น s1 = 1; S1 = S1 + 1; เนื่องจาก 1 เป็นประเภท int ผลลัพธ์ของการดำเนินการ S1+1 จึงเป็นประเภท INT และต้องใช้ประเภทการหล่อเพื่อกำหนดค่าให้กับประเภทสั้น ๆ และสั้น S1 = 1; S1 += 1; สามารถรวบรวมได้อย่างถูกต้องเนื่องจาก S1+= 1; เทียบเท่ากับ S1 = (สั้น) (S1 + 1); มีการปลดเปลื้องโดยนัย
6. มี goto ใน Java หรือไม่?
คำตอบ: Goto เป็นคำที่สงวนไว้ใน Java และไม่ได้ใช้ใน Java เวอร์ชันปัจจุบัน (รายการคำหลักของ Java มีให้ในภาคผนวกของหนังสือ "The Java Programming Language" ที่เขียนโดย James Gosling (พ่อของ Java) ซึ่งรวมถึง Goto และ Const แต่ทั้งสองเป็นคำหลักที่ไม่สามารถใช้ได้ ได้รับการพิจารณาว่าสงวนไว้)
7. อะไรคือความแตกต่างระหว่าง int และจำนวนเต็ม?
คำตอบ: Java เป็นภาษาการเขียนโปรแกรมเชิงวัตถุเกือบบริสุทธิ์ แต่เพื่อความสะดวกในการเขียนโปรแกรมมันยังคงแนะนำประเภทข้อมูลพื้นฐานที่ไม่ใช่วัตถุ อย่างไรก็ตามเพื่อใช้งานประเภทข้อมูลพื้นฐานเหล่านี้เป็นวัตถุ Java ได้แนะนำคลาส wrapper ที่สอดคล้องกันสำหรับแต่ละประเภทข้อมูลพื้นฐาน คลาสบรรจุภัณฑ์ของ INT เป็นจำนวนเต็ม ตั้งแต่ JDK 1.5 มีการแนะนำกลไกการบรรจุ/ยกเลิกการกล่องอัตโนมัติเพื่อให้ทั้งสองสามารถแปลงกันได้
Java จัดเตรียมประเภท wrapper สำหรับแต่ละประเภทดั้งเดิม:
ประเภทดั้งเดิม: บูลีน, ถ่าน, ไบต์, สั้น, int, ยาว, ลอย, double
ประเภทบรรจุภัณฑ์: บูลีน, ตัวละคร, ไบต์, สั้น, จำนวนเต็ม, ยาว, ลอย, double
แพ็คเกจ com.lovo; // ทำไมถามเกี่ยวกับ hovertree.compublic คลาส autounboxingTest {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม A = จำนวนเต็มใหม่ (3); จำนวนเต็ม b = 3; // กล่องอัตโนมัติ 3 เป็นจำนวนเต็มประเภท int c = 3; System.out.println (a == b); // FALSE การอ้างอิงทั้งสองไม่ได้อ้างอิง System.Out.out.println (A == C); // true a unboxes โดยอัตโนมัติเป็นประเภท int จากนั้นเปรียบเทียบกับ c}}เพิ่ม: ฉันเพิ่งพบคำถามสัมภาษณ์ซึ่งเกี่ยวข้องกับการบรรจุอัตโนมัติและการยกเลิกการบ็อกซ์รหัสมีดังนี้:
ระดับสาธารณะ test03 {โมฆะคงที่สาธารณะหลัก (สตริง [] args) {จำนวนเต็ม f1 = 100, f2 = 100, f3 = 150, f4 = 150; System.out.println (F1 == F2); System.out.println (F3 == F4); }} // hovertree.comหากคุณไม่เข้าใจมันเป็นเรื่องง่ายที่จะคิดว่าผลลัพธ์ทั้งสองนั้นเป็นจริงหรือเท็จ ประการแรกมันเป็นสิ่งสำคัญที่จะต้องทราบว่าตัวแปรทั้งสี่ตัวแปร F1, F2, F3 และ F4 เป็นวัตถุจำนวนเต็มทั้งหมดดังนั้นการดำเนินการ == ต่อไปนี้จะเปรียบเทียบค่าไม่ใช่ค่า แต่การอ้างอิง สาระสำคัญของการบรรจุคืออะไร? เมื่อเรากำหนดค่า int ให้กับวัตถุจำนวนเต็มเราจะเรียกค่าวิธีการคงที่ของคลาสจำนวนเต็ม หากเราดูซอร์สโค้ดของค่าเราจะรู้ว่าเกิดอะไรขึ้น
ค่าคงที่ค่าคงที่สาธารณะของสาธารณะ (int i) {ถ้า (i> = integercache.low && i <= integercache.high) ส่งคืน integercache.cache [i + (-integercache.low)]; ส่งคืนจำนวนเต็มใหม่ (i); } // hovertree.comIntegerCache เป็นระดับภายในของจำนวนเต็มและรหัสของมันมีลักษณะเช่นนี้:
/** * แคชเพื่อรองรับความหมายของตัวตนของวัตถุของ autoboxing สำหรับค่าระหว่าง * -128 และ 127 (รวม) ตามที่ JLS ต้องการ * * แคชเริ่มต้นจากการใช้งานครั้งแรก ขนาดของแคช * อาจถูกควบคุมโดยตัวเลือก {@code -xx: AutoboxCachemax = <size>} * ในระหว่างการเริ่มต้น VM, java.lang.integer.integercache.high คุณสมบัติ * อาจถูกตั้งค่าและบันทึกไว้ในคุณสมบัติของระบบส่วนตัวในคลาส * sun.misc.vm * hovertree.com */ คลาสคงที่คลาสคงที่ integercache {คงสุดท้าย int low = -128; int สุดท้ายคงที่สูง; แคชจำนวนเต็มสุดท้ายคงที่ []; {// ค่าสูงอาจถูกกำหนดค่าโดยคุณสมบัติ int h = 127; String IntegercachehighPropValue = sun.misc.vm.gm.getSavedProperty ("java.lang.integer.integercache.high"); if (IntegerCachehighPropValue! = null) {ลอง {int i = parseInt (IntegerCachehighPropValue); i = math.max (i, 127); // ขนาดอาร์เรย์สูงสุดคือจำนวนเต็ม max_value h = math.min (i, integer.max_value -(-low) -1); } catch (numberFormatexception nfe) {// ถ้าคุณสมบัติไม่สามารถแยกวิเคราะห์เป็น int ได้ให้ละเว้น }} สูง = h; แคช = จำนวนเต็มใหม่ [(สูง - ต่ำ) + 1]; int j = ต่ำ; สำหรับ (int k = 0; k <cache.length; k ++) แคช [k] = จำนวนเต็มใหม่ (j ++); // ช่วง [-128, 127] ต้องถูกทำให้เป็นภายใน (jls7 5.1.7) ยืนยัน Integercache.high> = 127; } Private IntegerCache () {}}พูดง่ายๆคือถ้าค่าตัวอักษรอยู่ระหว่าง -128 ถึง 127 แล้ววัตถุจำนวนเต็มใหม่จะไม่ใหม่ แต่วัตถุจำนวนเต็มในพูลคงที่จะถูกอ้างอิงโดยตรง ดังนั้นผลลัพธ์ของ F1 == F2 ในคำถามสัมภาษณ์ข้างต้นจึงเป็นจริงและผลลัพธ์ของ F3 == F4 เป็นเท็จ คำถามสัมภาษณ์ที่ง่ายกว่านั้นยิ่งมีความลึกลับมากขึ้นและผู้สัมภาษณ์จำเป็นต้องมีทักษะมากมาย
8. อะไรคือความแตกต่างระหว่าง & &&?
คำตอบ: มีการใช้สองครั้งของผู้ดำเนินการ & (1) bitwise และ (2) ตรรกะและ ตัวดำเนินการ && เป็นวงจรลัดวงจรและการทำงาน ความแตกต่างระหว่างตรรกะและการลัดวงจรมีขนาดใหญ่มากแม้ว่าทั้งคู่ต้องการให้ค่าบูลีนที่ปลายด้านซ้ายและขวาของผู้ปฏิบัติงานนั้นเป็นจริงกับค่าของการแสดงออกทั้งหมด && เรียกว่าการดำเนินการลัดวงจรเพราะถ้าค่าของนิพจน์ทางด้านซ้ายของ && เป็นเท็จนิพจน์ทางด้านขวาจะถูกลัดวงจรโดยตรงและการดำเนินการจะไม่ถูกดำเนินการ หลายครั้งที่เราอาจต้องใช้ && แทน & ตัวอย่างเช่นเมื่อตรวจสอบว่าชื่อผู้ใช้ไม่ได้เป็นโมฆะและไม่ใช่สตริงที่ว่างเปล่าควรเขียนเป็น: ชื่อผู้ใช้! = null &&! ชื่อผู้ใช้ Equals ("") คำสั่งของทั้งสองไม่สามารถแลกเปลี่ยนได้และไม่สามารถใช้ตัวดำเนินการ & ตัวดำเนินการได้เนื่องจากหากเงื่อนไขแรกไม่เป็นความจริงการเปรียบเทียบค่าเท่ากับของสตริงไม่สามารถทำได้เลยมิฉะนั้นจะมีการสร้าง nullpointerexception หมายเหตุ: สิ่งเดียวกันนี้เป็นจริงสำหรับความแตกต่างระหว่างตรรกะหรือตัวดำเนินการ (|) และลัดวงจรหรือตัวดำเนินการ (||)
เพิ่ม: หากคุณคุ้นเคยกับ JavaScript คุณอาจรู้สึกถึงพลังของการคำนวณการลัดวงจรมากขึ้น หากคุณต้องการเป็นหลักของ JavaScript ให้เริ่มต้นด้วยการเล่นคอมพิวเตอร์ลัดวงจร
9. อธิบายการใช้งานสแต็กกองและพื้นที่เก็บข้อมูลคงที่ในหน่วยความจำ
คำตอบ: โดยปกติเราจะกำหนดตัวแปรของชนิดข้อมูลพื้นฐานการอ้างอิงวัตถุและที่เก็บข้อมูลในสถานที่ของฟังก์ชั่นการเรียกทั้งหมดใช้พื้นที่สแต็กในหน่วยความจำ และวัตถุที่สร้างขึ้นผ่านคำหลักใหม่และตัวสร้างจะถูกวางไว้ในพื้นที่ฮีป ตัวอักษรในโปรแกรมเช่น 100, "สวัสดี" และค่าคงที่ที่เขียนโดยตรงจะถูกวางไว้ในพื้นที่เก็บข้อมูลแบบคงที่ สแต็กพื้นที่ทำงานเร็วที่สุด แต่ก็มีขนาดเล็กมาก โดยปกติแล้ววัตถุจำนวนมากจะถูกวางไว้ในพื้นที่ฮีปและหน่วยความจำทั้งหมดรวมถึงหน่วยความจำเสมือนบนฮาร์ดดิสก์สามารถใช้เป็นพื้นที่ฮีปได้
string str = สตริงใหม่ ("สวัสดี");
ในคำแถลงข้างต้น Str ถูกวางไว้บนสแต็กวัตถุสตริงที่สร้างขึ้นด้วยใหม่จะถูกวางไว้บนกองและตัวอักษร "สวัสดี" จะถูกวางไว้ในพื้นที่เก็บข้อมูลแบบคงที่
ภาคผนวก: Java รุ่นใหม่กว่าใช้เทคโนโลยีที่เรียกว่า "การวิเคราะห์หลบหนี" ซึ่งสามารถวางวัตถุท้องถิ่นบางอย่างบนสแต็กเพื่อปรับปรุงประสิทธิภาพการทำงานของวัตถุ
10. Math.Round (11.5) เท่ากับอะไร? Math.round (-11.5) เท่ากับอะไร?
คำตอบ: ค่าส่งคืนของ Math.Round (11.5) คือ 12 และค่าส่งคืนของ Math.Round (-11.5) คือ -11 หลักการของการปัดเศษคือการเพิ่ม 0.5 ลงในพารามิเตอร์แล้วปัดเศษลง
11. Swtich สามารถทำหน้าที่ไบต์ได้นานแล้วหรือไม่?
คำตอบ: ในช่วงต้น JDK ในสวิตช์ (expr) expr สามารถเป็นไบต์, สั้น, ถ่านและ int เริ่มต้นจากเวอร์ชัน 1.5 Java ได้แนะนำประเภท enum (enums) และ expr สามารถเป็น enums เริ่มจากเวอร์ชัน 1.7 ของ JDK และสตริง (สตริง) ไม่อนุญาตให้ใช้ประเภทยาว
12. ใช้วิธีที่มีประสิทธิภาพมากที่สุดในการคำนวณ 2 ครั้ง 8?
คำตอบ: 2 << 3 (การเคลื่อนย้าย 3 บิตทางด้านซ้ายเทียบเท่ากับการคูณด้วย 2 ถึงพลังของ 3 และการเคลื่อนย้าย 3 บิตทางด้านขวาเทียบเท่ากับการหารด้วย 2 ถึงพลัง 3)
ภาคผนวก: เมื่อเราเขียนวิธี HashCode ใหม่สำหรับคลาสที่เราเขียนเราอาจเห็นรหัสที่แสดงด้านล่าง ในความเป็นจริงเราไม่ค่อยเข้าใจว่าทำไมเราถึงใช้การคูณดังกล่าวเพื่อสร้างรหัสแฮช (รหัสแฮช) และทำไมหมายเลขนี้ถึงเป็นหมายเลขสำคัญและทำไมหมายเลข 31 จึงถูกเลือก คุณสามารถ Baidu ในคำตอบของคำถามสองข้อแรก เลือก 31 เนื่องจากการดำเนินการกะและการลบสามารถใช้แทนการคูณได้ดังนั้นจึงบรรลุประสิทธิภาพที่ดีขึ้น เมื่อพูดถึงสิ่งนี้คุณอาจคิดว่า: 31 * num <==> (num << 5) - num การเปลี่ยน 5 บิตซ้ายเทียบเท่ากับการคูณด้วย 2 ถึงพลังงานที่ 5 (32) และการลบตัวเองเทียบเท่ากับการคูณด้วย 31 VM ทั้งหมดสามารถปรับการปรับให้เหมาะสมนี้โดยอัตโนมัติ
แพ็คเกจ com.loonstudio; phonenumber ระดับสาธารณะ {private int arearecode; คำนำหน้าสตริงส่วนตัว; ผ้าลินินสตริงส่วนตัว; @Override public int hashCode () {สุดท้าย int prime = 31; int ผลลัพธ์ = 1; result = prime * result + areaCode; result = prime * result + ((linenumber == null)? 0: linenumber.hashCode ()); result = prime * result + ((คำนำหน้า == null)? 0: prefix.hashCode ()); ผลการกลับมา; } @Override บูลีนสาธารณะเท่ากับ (Object obj) {ถ้า (this == obj) คืนค่าจริง; ถ้า (obj == null) ส่งคืนเท็จ; ถ้า (getClass ()! = obj.getClass ()) ส่งคืนเท็จ; Phonenumber อื่น ๆ = (phonenumber) obj; if (areaCode! = other.areacode) ส่งคืน false; if (linenumber == null) {ถ้า (อื่น ๆ linenumber! = null) return false; } else ถ้า (! linenumber.equals (อื่น ๆ . linenumber)) ส่งคืนเท็จ; if (prefix == null) {ถ้า (อื่น ๆ (อื่น ๆ prefix! = null) ส่งคืน false; } อื่นถ้า (! prefix.equals (อื่น ๆ . prefix)) ส่งคืนเท็จ; กลับมาจริง; }} // ทำไมถามเกี่ยวกับ hovertree.com13. มีวิธีความยาว () สำหรับอาร์เรย์หรือไม่? มีวิธีการยาว () สำหรับสตริงหรือไม่?
คำตอบ: อาร์เรย์ไม่มีวิธีความยาว () แต่มีแอตทริบิวต์ความยาว สตริงมีวิธีความยาว () ใน JavaScript การได้รับความยาวของสตริงจะได้รับผ่านแอตทริบิวต์ความยาวซึ่งสับสนกับ Java ได้ง่าย
14. ใน Java วิธีการแยกออกจากห่วงซ้อนกันหลายตัวในปัจจุบัน?
คำตอบ: เพิ่มเครื่องหมายเช่นก่อนวนรอบด้านนอกสุดจากนั้นใช้ Break A; หลายลูปสามารถหักได้ (Java รองรับการติดแท็กเบรคและดำเนินการต่อและฟังก์ชั่นของพวกเขาคล้ายกับคำสั่ง goto ใน C และ C ++ แต่เช่นเดียวกับการหลีกเลี่ยง Goto คุณควรหลีกเลี่ยงการหยุดพักติดแท็กและดำเนินการต่อเพราะมันจะไม่ทำให้โปรแกรมของคุณสง่างามมากขึ้นและมักจะมีผลตรงกันข้าม
15. ตัวสร้างสามารถแทนที่ได้หรือไม่?
คำตอบ: ตัวสร้างไม่สามารถสืบทอดได้ดังนั้นจึงไม่สามารถเขียนใหม่ได้
16. วัตถุสองชิ้นมีค่าเท่ากัน (x.equals (y) == true) แต่พวกเขาสามารถมีรหัสแฮชที่แตกต่างกัน ใช่ไหม
คำตอบ: ไม่ถ้าวัตถุทั้งสอง x และ y ตอบสนอง x.equals (y) == จริงรหัสแฮชของพวกเขาควรจะเหมือนกัน Java กำหนดวิธี EQAULS และวิธีการ HashCode ดังนี้: (1) หากวัตถุสองวัตถุเหมือนกัน (วิธีการเท่ากับผลตอบแทนจริง) ดังนั้นค่า hashcode ของพวกเขาจะต้องเหมือนกัน; (2) หาก hashcodes ของวัตถุทั้งสองเหมือนกันพวกเขาไม่จำเป็นต้องเหมือนกัน แน่นอนว่าคุณไม่จำเป็นต้องทำตามที่ต้องการ แต่ถ้าคุณละเมิดหลักการข้างต้นคุณจะพบว่าเมื่อใช้คอนเทนเนอร์วัตถุเดียวกันสามารถปรากฏในชุดสะสมและประสิทธิภาพของการเพิ่มองค์ประกอบใหม่จะลดลงอย่างมาก (สำหรับระบบที่ใช้การจัดเก็บแฮชความขัดแย้งบ่อยครั้งในรหัสแฮช
ภาคผนวก: โปรแกรม Java หลายโปรแกรมรู้เกี่ยวกับวิธีการที่เท่าเทียมกันและวิธีการ HashCode แต่หลายคนเพิ่งรู้ ในผลงานชิ้นเอกของ Joshua Bloch "Java" (บริษัท ซอฟต์แวร์หลายแห่ง "Java ที่มีประสิทธิภาพ", "ความคิดการเขียนโปรแกรม Java" และ "refactoring: การปรับปรุงคุณภาพของรหัสที่มีอยู่" เป็นหนังสือที่ต้องอ่านโดยโปรแกรม Java หากคุณไม่ได้อ่าน จริง) และสมมาตร (x.equals (y) ส่งคืน true, y.equals (x) ไม่ว่าจะต้องส่งคืนจริง), transitiveness (x.equals (y) และ y.equals (z) จะต้องส่งคืนจริง) และความสอดคล้อง (เมื่อข้อมูลวัตถุที่อ้างอิงโดย x และ y ไม่ได้แก้ไข เทคนิคในการใช้วิธีการเท่ากับคุณภาพสูง ได้แก่ : 1. ใช้ตัวดำเนินการ == เพื่อตรวจสอบว่า "พารามิเตอร์นั้นอ้างอิงถึงวัตถุนี้หรือไม่"; 2. ใช้ตัวดำเนินการอินสแตนซ์ของตัวดำเนินการเพื่อตรวจสอบ "ว่าพารามิเตอร์เป็นประเภทที่ถูกต้องหรือไม่"; 3. สำหรับแอตทริบิวต์คีย์ในชั้นเรียนตรวจสอบว่าแอตทริบิวต์ที่ส่งผ่านไปยังวัตถุนั้นตรงกับหรือไม่ 4. หลังจากเขียนวิธี Equals ถามตัวเองว่ามันเป็นไปตามความสมมาตรการขนส่งและความสอดคล้องหรือไม่ 5. เขียน hashcode ใหม่เสมอเมื่อเขียนใหม่เท่ากับ; 6. อย่าแทนที่วัตถุวัตถุในพารามิเตอร์เมธอดเท่ากับประเภทอื่น ๆ และอย่าลืมคำอธิบายประกอบ @Override เมื่อเขียนใหม่
17. คลาสสตริงสามารถสืบทอดได้หรือไม่?
คำตอบ: คลาสสตริงเป็นคลาสสุดท้ายและไม่สามารถสืบทอดได้
ภาคผนวก: การสืบทอดสตริงเป็นพฤติกรรมที่ผิดในตัวเอง วิธีที่ดีที่สุดในการใช้ประเภทสตริงซ้ำคือการเชื่อมโยง (HAS-A) มากกว่าการสืบทอด (IS-A)
18. เมื่อวัตถุถูกส่งผ่านเป็นพารามิเตอร์ไปยังวิธีการวิธีนี้สามารถเปลี่ยนคุณสมบัติของวัตถุและส่งคืนผลลัพธ์ที่เปลี่ยนแปลง มันเป็นค่าผ่านหรือผ่านการอ้างอิงที่นี่?
คำตอบ: มันคือการโอนค่า ภาษาการเขียนโปรแกรม Java ผ่านพารามิเตอร์ที่มีค่าเท่านั้น เมื่ออินสแตนซ์ของวัตถุถูกส่งไปยังวิธีเป็นพารามิเตอร์ค่าของพารามิเตอร์คือการอ้างอิงไปยังวัตถุ คุณสมบัติของวัตถุสามารถเปลี่ยนแปลงได้ในระหว่างกระบวนการโทร แต่การอ้างอิงถึงวัตถุจะไม่เปลี่ยนแปลง ใน C ++ และ C#ค่าของพารามิเตอร์ที่ผ่านสามารถเปลี่ยนแปลงได้โดยผ่านการอ้างอิงหรือการถ่ายโอนพารามิเตอร์
ภาคผนวก: มันไม่สะดวกที่จะไม่ผ่านการอ้างอิงใน Java ซึ่งไม่ได้รับการปรับปรุงใน Java 8 มันเป็นวิธีนี้อย่างแม่นยำว่าคลาส wrapper จำนวนมากปรากฏขึ้นในรหัสที่เขียนใน Java วิธีการนี้จะทำให้รหัสป่องโดยเฉพาะอย่างยิ่งสำหรับนักพัฒนาที่เปลี่ยนจาก C และ C ++ เป็นโปรแกรมเมอร์ Java เป็นทนไม่ได้
19. อะไรคือความแตกต่างระหว่าง String และ StringBuilder และ StringBuffer?
คำตอบ: แพลตฟอร์ม Java มีสองประเภทของสตริง: String และ StringBuffer/StringBuilder ซึ่งสามารถจัดเก็บและจัดการสตริงได้ ในกรณีที่สตริงเป็นสตริงแบบอ่านอย่างเดียวซึ่งหมายความว่าเนื้อหาของสตริงที่อ้างอิงโดยสตริงไม่สามารถเปลี่ยนแปลงได้ วัตถุสตริงที่แสดงโดยคลาส StringBuffer และ StringBuilder สามารถแก้ไขได้โดยตรง StringBuilder ได้รับการแนะนำใน JDK 1.5 มันเหมือนกับวิธีการของ StringBuffer ความแตกต่างคือมันถูกใช้ในสภาพแวดล้อมเธรดเดียวเพราะทุกแง่มุมของมันไม่ได้รับการแก้ไขโดยการซิงโครไนซ์ดังนั้นจึงมีประสิทธิภาพมากกว่า StringBuffer เล็กน้อย
ภาคผนวก 1: มีคำถามสัมภาษณ์: มีสถานการณ์ใดบ้างที่ใช้ + เพื่อทำสตริงการรวมกันดีกว่าการเรียกใช้วิธีการที่ผนวกของวัตถุ StringBuffer/StringBuilder? หากสตริงที่ได้รับหลังจากการเชื่อมต่อมีอยู่แล้วในพื้นที่เก็บข้อมูลแบบคงที่การใช้ + สำหรับการเชื่อมต่อสตริงจะดีกว่าวิธีการผนวกของ StringBuffer/StringBuilder
ภาคผนวก 2: ต่อไปนี้เป็นคำถามสัมภาษณ์โดยถามผลลัพธ์ของโปรแกรมเพื่อดูว่าคุณสามารถให้คำตอบที่ถูกต้องได้หรือไม่
แพ็คเกจ com.lovo; // ทำไมถามเกี่ยวกับ hovertree.compublic คลาส stringequaltest {โมฆะคงที่สาธารณะหลัก (String [] args) {string a = "การเขียนโปรแกรม"; สตริง b = สตริงใหม่ ("การเขียนโปรแกรม"); String C = "Program" + "Ming"; System.out.println (a == b); System.out.println (a == c); System.out.println (A.Equals (B)); System.out.println (A.Equals (C)); System.out.println (a.intern () == b.intern ()); -20. ความแตกต่างระหว่างการโอเวอร์โหลดและการแทนที่ วิธีการโอเวอร์โหลดสามารถแยกแยะได้ตามประเภทการส่งคืนได้หรือไม่?
คำตอบ: ทั้งสองวิธีที่โอเวอร์โหลดและการเขียนใหม่เป็นวิธีที่จะใช้ polymorphism ความแตกต่างคืออดีตอุปกรณ์รวบรวมความหลากหลายเวลาในการรวบรวมเวลาในขณะที่หลังใช้ polymorphism run-time โอเวอร์โหลดเกิดขึ้นในชั้นเรียน หากวิธีการที่มีชื่อเดียวกันมีรายการพารามิเตอร์ที่แตกต่างกัน (ประเภทพารามิเตอร์ที่แตกต่างกันจำนวนพารามิเตอร์ที่แตกต่างกันหรือทั้งสองอย่าง) จะถือว่าเป็นโอเวอร์โหลด การเขียนใหม่เกิดขึ้นระหว่างคลาสย่อยและคลาสแม่ การเขียนใหม่ต้องการให้วิธีการเขียนใหม่ของคลาสย่อยและคลาสพาเรนต์มีประเภทผลตอบแทนเดียวกันกับวิธีการเขียนใหม่ของคลาสแม่ซึ่งเป็นการเข้าถึงที่ดีกว่าวิธีการเขียนใหม่ของคลาสแม่และไม่สามารถประกาศข้อยกเว้นได้มากกว่าวิธีการเขียนใหม่ของคลาสแม่ (หลักการทดแทนของ Rischer) การโอเวอร์โหลดไม่มีข้อกำหนดพิเศษสำหรับประเภทการส่งคืน
ภาคผนวก: Huawei เคยถามคำถามในคำถามสัมภาษณ์: ทำไมคุณไม่สามารถแยกแยะความแตกต่างของการโอเวอร์โหลดตามประเภทการส่งคืนและบอกคำตอบของคุณ!
21. อธิบายหลักการและกลไกของไฟล์คลาสการโหลด JVM?
คำตอบ: การโหลดคลาสใน JVM ถูกนำไปใช้โดยตัวโหลดคลาส (classloader) และคลาสย่อย ตัวโหลดคลาสใน Java เป็นส่วนประกอบของระบบรันไทม์ Java ที่สำคัญซึ่งรับผิดชอบในการค้นหาและโหลดคลาสในไฟล์คลาสที่รันไทม์
เติมเต็ม:
1. เนื่องจากลักษณะข้ามแพลตฟอร์มของ Java โปรแกรมแหล่ง Java ที่รวบรวมได้ไม่ใช่โปรแกรมที่สามารถเรียกใช้งานได้ แต่เป็นไฟล์คลาสหนึ่งไฟล์ขึ้นไป เมื่อโปรแกรม Java จำเป็นต้องใช้คลาส JVM จะช่วยให้มั่นใจได้ว่าคลาสได้รับการโหลดเชื่อมต่อ (ตรวจสอบเตรียมและแยกวิเคราะห์) และเริ่มต้น การโหลดคลาสหมายถึงการอ่านข้อมูลจากไฟล์คลาส. class ลงในหน่วยความจำ โดยปกติแล้วการสร้างอาร์เรย์ไบต์เพื่ออ่านลงในไฟล์. class จากนั้นสร้างวัตถุคลาสที่สอดคล้องกับคลาสที่โหลด หลังจากการโหลดเสร็จสิ้นวัตถุคลาสยังไม่สมบูรณ์ดังนั้นคลาสจึงไม่สามารถใช้ได้ในเวลานี้ เมื่อคลาสถูกโหลดมันจะเข้าสู่ขั้นตอนการเชื่อมต่อ ขั้นตอนนี้มีสามขั้นตอน: การตรวจสอบการเตรียม (การจัดสรรหน่วยความจำสำหรับตัวแปรคงที่และการตั้งค่าเริ่มต้นเริ่มต้นเริ่มต้น) และการแยกวิเคราะห์ (แทนที่การอ้างอิงสัญลักษณ์ด้วยการอ้างอิงโดยตรง) ในที่สุด JVM เริ่มต้นคลาสรวมถึง: 1. หากคลาสมีคลาสหลักโดยตรงและคลาสยังไม่ได้เริ่มต้นแล้วคลาสแม่จะเริ่มต้นก่อน 2. หากมีคำสั่งเริ่มต้นในชั้นเรียนคำสั่งการเริ่มต้นเหล่านี้จะถูกดำเนินการในทางกลับกัน
2. การโหลดคลาสทำได้โดยคลาสโหลดเดอร์ซึ่งรวมถึง: รูทโหลดเดอร์ (bootstrap), ตัวโหลดส่วนขยาย (ส่วนขยาย), ตัวโหลดระบบ (ระบบ) และตัวโหลดคลาสที่ผู้ใช้กำหนด (subclass ของ java.lang.classloader) เริ่มต้นจาก JDK 1.2 กระบวนการโหลดคลาสใช้กลไกการมอบหมายของพ่อ (PDM) PDM ช่วยให้มั่นใจได้ถึงความปลอดภัยของแพลตฟอร์ม Java ในกลไกนี้ bootstrap ของ JVM คือตัวโหลดรูทและตัวโหลดอื่น ๆ มีและมีตัวโหลดคลาสแม่เพียงตัวเดียวเท่านั้น การโหลดคลาสก่อนร้องขอตัวโหลดคลาสพาเรนต์ให้โหลดและตัวโหลดคลาสแม่จะโหลดโดยโหลดเดอร์คลาสย่อยเท่านั้นเมื่อไม่มีการเปิดเครื่อง JVM ไม่ได้ให้การอ้างอิงถึงโปรแกรม bootstrap ถึง Java นี่คือคำแนะนำบางอย่างสำหรับรถตักหลายชั้น:
A) Bootstrap: โดยทั่วไปจะใช้งานโดยใช้รหัสท้องถิ่นและรับผิดชอบในการโหลดไลบรารีคลาส Core Basic ของ JVM (RT.JAR);
b) ส่วนขยาย: โหลดไลบรารีคลาสจากไดเรกทอรีที่ระบุโดยคุณสมบัติระบบ java.ext.dirs และตัวโหลดหลักของมันคือ bootstrap;
C) ระบบ: หรือที่เรียกว่า Loader คลาสแอปพลิเคชันคลาสแม่คือส่วนขยาย มันเป็นตัวโหลดคลาสที่ใช้กันอย่างแพร่หลายที่สุด มันบันทึกคลาสจากไดเรกทอรีที่ระบุโดยตัวแปรสภาพแวดล้อม classpath หรือแอตทริบิวต์ระบบ java.class.path และเป็นตัวโหลดหลักเริ่มต้นของตัวโหลดที่ผู้ใช้กำหนด
22. ตัวละครจีนสามารถเก็บไว้ในตัวแปรประเภทถ่านได้หรือไม่? ทำไม
คำตอบ: ประเภทถ่านสามารถเก็บอักขระภาษาจีนได้เนื่องจากการเข้ารหัสที่ใช้ใน Java เป็น Unicode (ไม่มีการเลือกการเข้ารหัสเฉพาะและตัวละครจะถูกใช้โดยตรงในหมายเลขชุดอักขระซึ่งเป็นวิธีการรวมเป็นหนึ่งเดียว) ประเภทถ่านใช้เวลา 2 ไบต์ (16 บิต) ดังนั้นจึงไม่มีปัญหาที่จะใส่ภาษาจีน
ภาคผนวก: การใช้ Unicode หมายความว่าอักขระมีอาการแตกต่างกันทั้งภายในและภายนอก JVM และทั้งสอง Unicode ภายใน JVM เมื่ออักขระนี้ถูกถ่ายโอนจาก JVM ไปยังด้านนอก (ตัวอย่างเช่นเก็บไว้ในระบบไฟล์) จำเป็นต้องมีการแปลงการเข้ารหัส ดังนั้น Java จึงมีสตรีมไบต์และสตรีมอักขระเช่นเดียวกับสตรีมการแปลงที่แปลงระหว่างสตรีมอักขระและสตรีมไบต์เช่น inputStreamReader และ outputStreamReader คลาสทั้งสองนี้เป็นคลาสอะแดปเตอร์ระหว่างสตรีมไบต์และสตรีมอักขระและดำเนินการเกี่ยวกับการเข้ารหัสการแปลง สำหรับโปรแกรมเมอร์ C เพื่อให้การแปลงการเข้ารหัสเสร็จสมบูรณ์พวกเขาอาจพึ่งพาลักษณะของสหภาพ (สหภาพ/ชุมชน) ที่ใช้ร่วมกันเพื่อให้บรรลุ
23. ความคล้ายคลึงกันและความแตกต่างระหว่างคลาสนามธรรมและอินเทอร์เฟซคืออะไร?
คำตอบ: ทั้งคลาสนามธรรมและอินเทอร์เฟซไม่สามารถสร้างอินสแตนซ์ได้ แต่การอ้างอิงถึงคลาสนามธรรมและประเภทอินเตอร์เฟสสามารถกำหนดได้ หากคลาสสืบทอดคลาสนามธรรมหรือใช้อินเทอร์เฟซมันจะต้องใช้วิธีการนามธรรมทั้งหมดในนั้นมิฉะนั้นคลาสจะต้องประกาศว่าเป็นคลาสนามธรรม อินเทอร์เฟซเป็นนามธรรมมากกว่าคลาสนามธรรมเนื่องจากตัวสร้างสามารถกำหนดได้ในคลาสนามธรรมและสามารถมีวิธีการที่เป็นนามธรรมและวิธีการคอนกรีตในขณะที่ตัวสร้างไม่สามารถกำหนดในอินเทอร์เฟซและวิธีการทั้งหมดในพวกเขาเป็นวิธีนามธรรม สมาชิกในชั้นเรียนนามธรรมสามารถเป็นส่วนตัวค่าเริ่มต้นการป้องกันและสาธารณะในขณะที่สมาชิกในอินเทอร์เฟซเป็นสาธารณะทั้งหมด ตัวแปรสมาชิกสามารถกำหนดได้ในคลาสนามธรรมในขณะที่ตัวแปรสมาชิกที่กำหนดไว้ในอินเทอร์เฟซเป็นค่าคงที่ คลาสที่มีวิธีการนามธรรมจะต้องประกาศว่าเป็นคลาสนามธรรมและคลาสนามธรรมไม่จำเป็นต้องมีวิธีนามธรรม
24. อะไรคือความแตกต่างระหว่างคลาสซ้อนกันแบบสแตติกและชั้นเรียนภายใน (ชั้นใน)?
คำตอบ: คลาสซ้อนกันแบบคงที่เป็นคลาสชั้นในที่ประกาศว่าเป็นแบบคงที่ซึ่งสามารถสร้างอินสแตนซ์ได้โดยไม่ต้องพึ่งพาอินสแตนซ์ระดับภายนอก คลาสภายในปกติจะต้องมีการสร้างอินสแตนซ์หลังจากคลาสภายนอกถูกสร้างอินสแตนซ์และไวยากรณ์ดูค่อนข้างแปลกดังที่แสดงด้านล่าง
แพ็คเกจ com.lovo; / ** * คลาสโป๊กเกอร์ (เด็คโป๊กเกอร์) ทำไมถามเกี่ยวกับ hovertree.com * */ คลาสสาธารณะโป๊กเกอร์ {สตริงสแตติกส่วนตัว [] suites = {"spade", "กุหลาบ", "ดอกไม้หญ้า", "ลูกบาศก์"}; private static int [] faces = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13}; การ์ดส่วนตัว [] การ์ด; / *** Constructor**/ Public Poker () {cards = การ์ดใหม่ [52]; สำหรับ (int i = 0; i <suites.length; i ++) {สำหรับ (int j = 0; j <faces.length; j ++) {cards [i * 13+j] = การ์ดใหม่ (ห้องสวีท [i], faces [j]); }}} / ** * shuffle (สุ่มตามลำดับ) * * / public void shuffle () {สำหรับ (int i = 0, len = cards.length; i <len; i ++) {int index = (int) (math.random () * len); อุณหภูมิการ์ด = การ์ด [ดัชนี]; การ์ด [ดัชนี] = การ์ด [i]; การ์ด [i] = อุณหภูมิ; }} / *** ข้อตกลงการ์ด* @param ดัชนีตำแหน่งของข้อตกลง** / ข้อตกลงบัตรสาธารณะ (ดัชนี int) {การ์ดส่งคืน [ดัชนี]; } / ** * คลาสการ์ด (ชิ้นส่วนของโป๊กเกอร์) * [คลาสภายใน] * @author luo hao * * / บัตรเรียนสาธารณะ {ชุดสตริงส่วนตัว; // ชุดหน้าส่วนตัว // คะแนนการ์ดสาธารณะ (String Suite, int Face) {this.suite = Suite; this.face = Face; } @Override Public String ToString () {String facestr = ""; สวิตช์ (ใบหน้า) {กรณีที่ 1: facestr = "a"; หยุดพัก; กรณีที่ 11: facestr = "J"; หยุดพัก; กรณีที่ 12: facestr = "q"; หยุดพัก; กรณีที่ 13: facestr = "k"; หยุดพัก; ค่าเริ่มต้น: facestr = string.valueof (ใบหน้า); } return Suite + facestr; - คลาสทดสอบ:
แพ็คเกจ com.lovo; คลาส pokertest {โมฆะสาธารณะคงที่หลัก (สตริง [] args) {โป๊กเกอร์โป๊กเกอร์ = โป๊กเกอร์ใหม่ (); Poker.shuffle (); // shuffle poker.card c1 = poker.deal (0); // ให้บริการการ์ดใบแรก // สำหรับการ์ดคลาสภายในที่ไม่คงที่ // สามารถสร้างวัตถุการ์ดได้ผ่าน Object Object Object Poker External Class Poker.Card C2 = Poker.new Card ("Red Heart", 1); // สร้างการ์ดด้วยตัวเอง System.out.println (C1); // system.out.println (C2) แรก; // พิมพ์: Red Heart A}} // ทำไมถามเกี่ยวกับ hovertree.com25. จะมีหน่วยความจำรั่วในชวาหรือไม่? โปรดอธิบายสั้น ๆ
คำตอบ: ในทางทฤษฎีแล้ว Java จะไม่มีการรั่วไหลของหน่วยความจำเนื่องจากมีกลไกการรวบรวมขยะ (GC) (นี่เป็นเหตุผลสำคัญว่าทำไม Java จึงถูกใช้อย่างกว้างขวางในการเขียนโปรแกรมฝั่งเซิร์ฟเวอร์); อย่างไรก็ตามในการพัฒนาจริงอาจมีวัตถุที่ไร้ประโยชน์ แต่สามารถเข้าถึงได้และวัตถุเหล่านี้ไม่สามารถรีไซเคิลได้โดย GC และการรั่วไหลของหน่วยความจำจะเกิดขึ้น ตัวอย่างคือวัตถุในเซสชันของไฮเบอร์เนต (ระดับแคชหนึ่ง) นั้นคงอยู่และตัวเก็บขยะจะไม่รีไซเคิลวัตถุเหล่านี้ แต่อาจมีวัตถุขยะที่ไร้ประโยชน์ในวัตถุเหล่านี้ ตัวอย่างต่อไปนี้ยังแสดงการรั่วไหลของหน่วยความจำใน Java:
แพ็คเกจ com.lovo; // ทำไมถามเกี่ยวกับ hovertree.commport java.util.arrays; นำเข้า java.util.emptystackexception; Mystack ชั้นเรียนสาธารณะ <t> {องค์ประกอบส่วนตัว t []; ขนาด int ส่วนตัว = 0; INT_CAPACITION INT_CAPACITY ส่วนตัว = 16; public MyStack() { elements = (T[]) new Object[INIT_CAPACITY]; } public void push(T elem) { ensureCapacity(); elements[size++] = elem; } public T pop() { if(size == 0) throw new EmptyStackException(); return elements[--size]; } private void ensureCapacity() { if(elements.length == size) { elements = Arrays.copyOf(elements, 2 * size + 1); -上面的代码实现了一个栈(先进后出(FILO))结构,乍看之下似乎没有什么明显的问题,它甚至可以通过你编写的各种单元测试。然而其中的pop方法却存在内存泄露的问题,当我们用pop方法弹出栈中的对象时,该对象不会被当作垃圾回收,即使使用栈的程序不再引用这些对象,因为栈内部维护着对这些对象的过期引用(obsolete reference)。在支持垃圾回收的语言中,内存泄露是很隐蔽的,这种内存泄露其实就是无意识的对象保持。如果一个对象引用被无意识的保留起来了,那么垃圾回收器不会处理这个对象,也不会处理该对象引用的其他对象,即使这样的对象只有少数几个,也可能会导致很多的对象被排除在垃圾回收之外,从而对性能造成重大影响,极端情况下会引发Disk Paging(物理内存与硬盘的虚拟内存交换数据),甚至造成OutOfMemoryError。
26、抽象的(abstract)方法是否可同时是静态的(static),是否可同时是本地方法(native),是否可同时被synchronized修饰?
答:都不能。抽象方法需要子类重写,而静态的方法是无法被重写的,因此二者是矛盾的。本地方法是由本地代码(如C代码)实现的方法,而抽象方法是没有实现的,也是矛盾的。synchronized和方法的实现细节有关,抽象方法不涉及实现细节,因此也是相互矛盾的。
27、静态变量和实例变量的区别?
答:静态变量是被static修饰符修饰的变量,也称为类变量,它属于类,不属于类的任何一个对象,一个类不管创建多少个对象,静态变量在内存中有且仅有一个拷贝;实例变量必须依存于某一实例,需要先创建对象然后通过对象才能访问到它。静态变量可以实现让多个对象共享内存。在Java开发中,上下文类和工具类中通常会有大量的静态成员。
28、是否可以从一个静态(static)方法内部发出对非静态(non-static)方法的调用?
答:不可以,静态方法只能访问静态成员,因为非静态方法的调用要先创建对象,因此在调用静态方法时可能对象并没有被初始化。
29、如何实现对象克隆?
答:有两种方式:
1.实现Cloneable接口并重写Object类中的clone()方法;
2.实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下。
package com.lovo; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; public class MyUtil { private MyUtil() { throw new AssertionError(); } public static <T> T clone(T obj) throws Exception { ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bout); oos.writeObject(obj); ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bin); return (T) ois.readObject(); // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义// 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源} } //何问起hovertree.com下面是测试代码:
package com.lovo; import java.io.Serializable; /** * Human* @author Luo Hao* */ class Person implements Serializable { private static final long serialVersionUID = -9102017020286042305L; private String name; // Name private int age; // Age private Car car; // Car public Person(String name, int age, Car car) { this.name = name; this.age = age; this.car = car; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Car getCar() { return car; } public void setCar(Car car) { this.car = car; } @Override public String toString() { return "Person [name=" + name + ", age=" + age + ", car=" + car + "]"; } } /** * Car class* @author Luo Hao* */ class Car implements Serializable { private static final long serialVersionUID = -5713945027627603702L; private String brand; // Brand private int maxSpeed; // Top speed public Car(String brand, int maxSpeed) { this.brand = brand; this.maxSpeed = maxSpeed; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public int getMaxSpeed() { return maxSpeed; } public void setMaxSpeed(int maxSpeed) { this.maxSpeed = maxSpeed; } @Override public String toString() { return "Car [brand=" + brand + ", maxSpeed=" + maxSpeed + "]"; } } //Why ask about hovertree.comclass CloneTest { public static void main(String[] args) { try { Person p1 = new Person("Hao LUO", 33, new Car("Benz", 300)); Person p2 = MyUtil.clone(p1); // Deep cloning p2.getCar().setBrand("BYD"); // Modify the brand attributes of the cloned Person object p2-associated car object// The original Person object p1-associated car will not be affected in any way// Because when cloning Person object, the car object associated with it is also cloned System.out.println(p1); } catch (Exception e) { e.printStackTrace(); -注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。
30、GC 是什么?为什么要有GC?
答: GC是垃圾收集的意思,内存处理是编程人员容易出现问题的地方,忘记或者错误的内存回收会导致程序或系统的不稳定甚至崩溃,Java提供的GC功能可以自动监测对象是否超过作用域从而达到自动回收内存的目的,Java语言没有提供释放已分配内存的显示操作方法。Java程序员不用担心内存管理,因为垃圾收集器会自动进行管理。要请求垃圾收集,可以调用下面的方法之一:System.gc() 或Runtime.getRuntime().gc() ,但JVM可以屏蔽掉显示的垃圾回收调用。
垃圾回收可以有效的防止内存泄露,有效的使用可以使用的内存。垃圾回收器通常是作为一个单独的低优先级的线程运行,不可预知的情况下对内存堆中已经死亡的或者长时间没有使用的对象进行清除和回收,程序员不能实时的调用垃圾回收器对某个对象或所有对象进行垃圾回收。在Java诞生初期,垃圾回收是Java最大的亮点之一,因为服务器端的编程需要有效的防止内存泄露问题,然而时过境迁,如今Java的垃圾回收机制已经成为被诟病的东西。移动智能终端用户通常觉得iOS的系统比Android系统有更好的用户体验,其中一个深层次的原因就在于Android系统中垃圾回收的不可预知性。
补充:垃圾回收机制有很多种,包括:分代复制垃圾回收、标记垃圾回收、增量垃圾回收等方式。标准的Java进程既有栈又有堆。栈保存了原始型局部变量,堆保存了要创建的对象。Java平台对堆内存回收和再利用的基本算法被称为标记和清除,但是Java对其进行了改进,采用“分代式垃圾收集”。这种方法会跟Java对象的生命周期将堆内存划分为不同的区域,在垃圾收集过程中,可能会将对象移动到不同区域:
伊甸园(Eden):这是对象最初诞生的区域,并且对大多数对象来说,这里是它们唯一存在过的区域。
幸存者乐园(Survivor):从伊甸园幸存下来的对象会被挪到这里。
终身颐养园(Tenured):这是足够老的幸存对象的归宿。年轻代收集(Minor-GC)过程是不会触及这个地方的。当年轻代收集不能把对象放进终身颐养园时,就会触发一次完全收集(Major-GC),这里可能还会牵扯到压缩,以便为大对象腾出足够的空间。
与垃圾回收相关的JVM参数:
-Xms / -Xmx --- 堆的初始大小/ 堆的最大大小
-Xmn --- 堆中年轻代的大小
-XX:-DisableExplicitGC --- 让System.gc()不产生任何作用
-XX:+PrintGCDetail --- 打印GC的细节
-XX:+PrintGCDateStamps --- 打印GC操作的时间戳
31、String s=new String(“xyz”);创建了几个字符串对象?
答:两个对象,一个是静态存储区的"xyz",一个是用new创建在堆上的对象。
32、接口是否可继承(extends)接口? 抽象类是否可实现(implements)接口? 抽象类是否可继承具体类(concrete class)?
答:接口可以继承接口。抽象类可以实现(implements)接口,抽象类可继承具体类,但前提是具体类必须有明确的构造函数。
33、一个“.java”源文件中是否可以包含多个类(不是内部类)?有什么限制?
答:可以,但一个源文件中最多只能有一个公开类(public class)而且文件名必须和公开类的类名完全保持一致。
34、Anonymous Inner Class(匿名内部类)是否可以继承其它类?是否可以实现接口?
答:可以继承其他类或实现其他接口,在Swing编程中常用此方式来实现事件监听和回调。
35、内部类可以引用它的包含类(外部类)的成员吗?有没有什么限制?
答:一个内部类对象可以访问创建它的外部类对象的成员,包括私有成员。
36、Java 中的final关键字有哪些用法?
答: (1)修饰类:表示该类不能被继承;(2)修饰方法:表示方法不能被重写;(3)修饰变量:表示变量只能一次赋值以后值不能被修改(常量)。
37、指出下面程序的运行结果:
class A{ static{ System.out.print("1"); } public A(){ System.out.print("2"); } } class B extends A{ static{ System.out.print("a"); } public B(){ System.out.print("b"); } } //Why ask about hovertree.compublic class Hello{ public static void main(String[] args){ A ab = new B(); ab = new B(); -答:执行结果:1a2b2b。创建对象时构造器的调用顺序是:先初始化静态成员,然后调用父类构造器,再初始化非静态成员,最后调用自身构造器。
38、数据类型之间的转换:
1)如何将字符串转换为基本数据类型?
2)如何将基本数据类型转换为字符串?
คำตอบ:
1)调用基本数据类型对应的包装类中的方法parseXXX(String)或valueOf(String)即可返回相应基本类型;
2)一种方法是将基本数据类型与空字符串(””)连接(+)即可获得其所对应的字符串;另一种方法是调用String 类中的valueOf(…)方法返回相应字符串
39、如何实现字符串的反转及替换?
答:方法很多,可以自己写实现也可以使用String或StringBuffer / StringBuilder中的方法。有一道很常见的面试题是用递归实现字符串反转,代码如下所示:
public static String reverse(String originStr) { if(originStr == null || originStr.length() <= 1) return originStr; return reverse(originStr.substring(1)) + originStr.charAt(0); } //何问起hovertree.com40、怎样将GB2312编码的字符串转换为ISO-8859-1编码的字符串?
答:代码如下所示:
String s1 = "你好";String s2 = newString(s1.getBytes("GB2312"), "ISO-8859-1");41、日期和时间:
1)如何取得年月日、小时分钟秒?
2)如何取得从1970年1月1日0时0分0秒到现在的毫秒数?
3)如何取得某月的最后一天?
4)如何格式化日期?
答:操作方法如下所示:
1)创建java.util.Calendar 实例,调用其get()方法传入不同的参数即可获得参数所对应的值
2)以下方法均可获得该毫秒数:
Calendar.getInstance().getTimeInMillis(); System.currentTimeMillis(); //何问起hovertree.com
3)示例代码如下:
Calendar time = Calendar.getInstance(); time.getActualMaximum(Calendar.DAY_OF_MONTH); //何问起hovertree.com
4)利用java.text.DataFormat 的子类(如SimpleDateFormat类)中的format(Date)方法可将日期格式化。
42、打印昨天的当前时刻。
คำตอบ:
public class YesterdayCurrent { public static void main(String[] args){ Calendar cal = Calendar.getInstance(); cal.add(Calendar.DATE, -1); System.out.println(cal.getTime()); } } //何问起hovertree.com43、比较一下Java 和JavaSciprt。
答: JavaScript 与Java是两个公司开发的不同的两个产品。Java 是原Sun 公司推出的面向对象的程序设计语言,特别适合于互联网应用程序开发;而JavaScript是Netscape公司的产品,为了扩展Netscape浏览器的功能而开发的一种可以嵌入Web页面中运行的基于对象和事件驱动的解释性语言,它的前身是LiveScript;而Java 的前身是Oak语言。
下面对两种语言间的异同作如下比较:
1)基于对象和面向对象:Java是一种真正的面向对象的语言,即使是开发简单的程序,必须设计对象;JavaScript是种脚本语言,它可以用来制作与网络无关的,与用户交互作用的复杂软件。它是一种基于对象(Object-Based)和事件驱动(Event-Driven)的编程语言。因而它本身提供了非常丰富的内部对象供设计人员使用;
2)解释和编译:Java 的源代码在执行之前,必须经过编译;JavaScript 是一种解释性编程语言,其源代码不需经过编译,由浏览器解释执行;
3)强类型变量和类型弱变量:Java采用强类型变量检查,即所有变量在编译之前必须作声明;JavaScript中变量声明,采用其弱类型。即变量在使用前不需作声明,而是解释器在运行时检查其数据类型;
4)代码格式不一样。
补充:上面列出的四点是原来所谓的标准答案中给出的。其实Java和JavaScript最重要的区别是一个是静态语言,一个是动态语言。目前的编程语言的发展趋势是函数式语言和动态语言。在Java中类(class)是一等公民,而JavaScript中函数(function)是一等公民。对于这种问题,在面试时还是用自己的语言回答会更加靠谱。
44、什么时候用assert?
答: assertion(断言)在软件开发中是一种常用的调试方式,很多开发语言中都支持这种机制。一般来说,assertion用于保证程序最基本、关键的正确性。assertion检查通常在开发和测试时开启。为了提高性能,在软件发布后, assertion检查通常是关闭的。在实现中,断言是一个包含布尔表达式的语句,在执行这个语句时假定该表达式为true;如果表达式计算为false,那么系统会报告一个AssertionError。
断言用于调试目的:
assert(a > 0); // throws an AssertionError if a <= 0
断言可以有两种形式:
assert Expression1;
assert Expression1 : Expression2 ;
Expression1 应该总是产生一个布尔值。
Expression2 可以是得出一个值的任意表达式;这个值用于生成显示更多调试信息的字符串消息。
断言在默认情况下是禁用的,要在编译时启用断言,需使用source 1.4 标记:
javac -source 1.4 Test.java
要在运行时启用断言,可使用-enableassertions 或者-ea 标记。
要在运行时选择禁用断言,可使用-da 或者-disableassertions 标记。
要在系统类中启用断言,可使用-esa 或者-dsa 标记。还可以在包的基础上启用或者禁用断言。可以在预计正常情况下不会到达的任何位置上放置断言。断言可以用于验证传递给私有方法的参数。不过,断言不应该用于验证传递给公有方法的参数,因为不管是否启用了断言,公有方法都必须检查其参数。不过,既可以在公有方法中,也可以在非公有方法中利用断言测试后置条件。另外,断言不应该以任何方式改变程序的状态。
45、Error 和Exception 有什么区别?
答: Error 表示系统级的错误和程序不必处理的异常,是恢复不是不可能但很困难的情况下的一种严重问题;比如内存溢出,不可能指望程序能处理这样的情况;Exception 表示需要捕捉或者需要程序进行处理的异常,是一种设计或实现问题;也就是说,它表示如果程序运行正常,从不会发生的情况。
Supplement: During the interview with Motorola in 2005, I asked a question like "If a process reports a stack overflow run-time error, what's the most possible cause?", giving four options a. lack of memory; ข. write on an invalid memory space; ค. recursive function calling; d. array index out of boundary. Java programs may also encounter StackOverflowError when running. This is an error that cannot be recovered, so I can only re-modify the code. The answer to this interview question is c. If you write recursion that cannot converge quickly, it is very likely to cause a stack overflow error, as shown below:
package com.lovo; public class StackOverflowErrorTest { public static void main(String[] args) { main(null); } } //何问起hovertree.com因此,用递归编写程序时一定要牢记两点:1. 递归公式;2. 收敛条件(什么时候就不再递归而是回溯了)。
46、try{}里有一个return语句,那么紧跟在这个try后的finally{}里的code会不会被执行,什么时候被执行,在return前还是后?
答:会执行,在方法返回调用者前执行。Java允许在finally中改变返回值的做法是不好的,因为如果存在finally代码块,try中的return语句不会立马返回调用者,而是记录下返回值待finally代码块执行完毕之后再向调用者返回其值,然后如果在finally中修改了返回值,这会对程序造成很大的困扰,C#中就从语法上规定不能做这样的事。
47、Java 语言如何进行异常处理,关键字:throws、throw、try、catch、finally分别如何使用?
答: Java 通过面向对象的方法进行异常处理,把各种不同的异常进行分类,并提供了良好的接口。在Java 中,每个异常都是一个对象,它是Throwable 类或其子类的实例。当一个方法出现异常后便抛出一个异常对象,该对象中包含有异常信息,调用这个对象的方法可以捕获到这个异常并进行处理。Java 的异常处理是通过5 个关键词来实现的:try、catch、throw、throws和finally。一般情况下是用try来执行一段程序,如果出现异常,系统会抛出(throw)一个异常,这时候你可以通过它的类型来捕捉(catch)它,或最后(finally)由缺省处理器来处理;try用来指定一块预防所有“异常”的程序;catch 子句紧跟在try块后面,用来指定你想要捕捉的“异常”的类型;throw 语句用来明确地抛出一个“异常”;throws用来标明一个成员函数可能抛出的各种“异常”;finally 为确保一段代码不管发生什么“异常”都被执行一段代码;可以在一个成员函数调用的外面写一个try语句,在这个成员函数内部写另一个try语句保护其他代码。每当遇到一个try 语句,“异常”的框架就放到栈上面,直到所有的try语句都完成。如果下一级的try语句没有对某种“异常”进行处理,栈就会展开,直到遇到有处理这种“异常”的try 语句。
48、运行时异常与受检异常有何异同?
答:异常表示程序运行过程中可能出现的非正常状态,运行时异常表示虚拟机的通常操作中可能遇到的异常,是一种常见运行错误,只要程序设计得没有问题通常就不会发生。受检异常跟程序运行的上下文环境有关,即使程序设计无误,仍然可能因使用的问题而引发。Java编译器要求方法必须声明抛出可能发生的受检异常,但是并不要求必须声明抛出未被捕获的运行时异常。异常和继承一样,是面向对象程序设计中经常被滥用的东西,神作《Effective Java》中对异常的使用给出了以下指导原则:
不要将异常处理用于正常的控制流(设计良好的API不应该强迫它的调用者为了正常的控制流而使用异常)
对可以恢复的情况使用受检异常,对编程错误使用运行时异常避免不必要的使用受检异常(可以通过一些状态检测手段来避免异常的发生)
优先使用标准的异常每个方法抛出的异常都要有文档保持异常的原子性不要在catch中忽略掉捕获到的异常
49、列出一些你常见的运行时异常?
คำตอบ:
ArithmeticException(算术异常)
ClassCastException (类转换异常)
IllegalArgumentException (非法参数异常)
IndexOutOfBoundsException (下表越界异常)
NullPointerException (空指针异常)
SecurityException (安全异常)
50、final, finally, finalize 的区别?
答: final:修饰符(关键字)有三种用法:如果一个类被声明为final,意味着它不能再派生出新的子类,即不能被继承,因此它和abstract是反义词。将变量声明为final,可以保证它们在使用中不被改变,被声明为final 的变量必须在声明时给定初值,而在以后的引用中只能读取不可修改。被声明为final 的方法也同样只能使用,不能在子类中被重写。finally:通常放在try…catch的后面构造总是执行代码块,这就意味着程序无论正常执行还是发生异常,这里的代码只要JVM不关闭都能执行,可以将释放外部资源的代码写在finally块中。finalize:Object类中定义的方法,Java中允许使用finalize() 方法在垃圾收集器将对象从内存中清除出去之前做必要的清理工作。这个方法是由垃圾收集器在销毁对象时调用的,通过重写finalize() 方法可以整理系统资源或者执行其他清理工作。
ข้างต้นเป็นเนื้อหาทั้งหมดของบทความนี้ I hope it will be helpful to everyone in the Java interview, and I hope everyone will support Wulin.com more.