JavaRush /จาวาบล็อก /Random-TH /คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก ส่วนที่ 1
Roman Beekeeper
ระดับ

คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก ส่วนที่ 1

เผยแพร่ในกลุ่ม
สวัสดีทุกท่าน ท่านสุภาพสตรีและสุภาพบุรุษ วิศวกรซอฟต์แวร์! มาพูดถึงคำถามสัมภาษณ์กันดีกว่า เกี่ยวกับสิ่งที่ต้องเตรียมและสิ่งที่ต้องรู้ นี่เป็นเหตุผลที่ดีที่จะทำซ้ำหรือศึกษาประเด็นเหล่านี้ตั้งแต่เริ่มต้น คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ตอนที่ 1 - 1ฉันมีคอลเลกชันคำถามที่พบบ่อยมากมายเกี่ยวกับ OOP, Java Syntax, ข้อยกเว้นใน Java, คอลเลกชันและมัลติเธรด ซึ่งฉันจะแบ่งออกเป็นหลายส่วนเพื่อความสะดวก สำคัญ:เราจะพูดถึง Java เวอร์ชันสูงสุด 8 เท่านั้น นวัตกรรมทั้งหมดจาก 9, 10, 11, 12, 13 จะไม่ถูกนำมาพิจารณาที่นี่ ยินดีต้อนรับความคิดเห็น / ความคิดเห็นเกี่ยวกับวิธีการปรับปรุงคำตอบ ขอให้มีความสุขกับการอ่าน ลุยเลย!

สัมภาษณ์ Java: คำถาม OOP

1. Java มีคุณสมบัติอะไรบ้าง?

คำตอบ:
  1. แนวคิด OOP:

    1. การวางแนววัตถุ
    2. มรดก;
    3. การห่อหุ้ม;
    4. ความหลากหลาย;
    5. สิ่งที่เป็นนามธรรม
  2. ข้ามแพลตฟอร์ม:โปรแกรม Java สามารถรันบนแพลตฟอร์มใดก็ได้โดยไม่ต้องแก้ไขใดๆ สิ่งเดียวที่คุณต้องการคือ JVM ที่ติดตั้ง (java virtual machine)

  3. ประสิทธิภาพสูง: JIT (คอมไพเลอร์ Just In Time) ช่วยให้มีประสิทธิภาพสูง JIT แปลงรหัสไบต์เป็นรหัสเครื่อง จากนั้น JVM จะเริ่มดำเนินการ

  4. มัลติเธรด:เธรดการดำเนินการที่เรียกว่าThread. JVM สร้างเธรดที่เรียกว่าmain thread. โปรแกรมเมอร์สามารถสร้างหลายเธรดโดยสืบทอดจากคลาส Thread หรือโดยการใช้อินเทอร์เฟRunnable

2. มรดกคืออะไร?

การสืบทอดหมายความว่าคลาสหนึ่งสามารถสืบทอด (“ ขยาย ”) คลาสอื่นได้ วิธีนี้ทำให้คุณสามารถนำโค้ดจากคลาสที่คุณสืบทอดมามาใช้ซ้ำได้ คลาสที่มีอยู่เรียกว่าsuperclassและคลาสที่ถูกสร้างขึ้นเรียกsubclassว่า พวกเขายังพูดparentและchild.
public class Animal {
   private int age;
}

public class Dog extends Animal {

}
Animalอยู่ ที่ไหนparentและDog- child_

3. การห่อหุ้มคืออะไร?

คำถามนี้มักเกิดขึ้นระหว่างการสัมภาษณ์นักพัฒนา Java การห่อหุ้มกำลังซ่อนการใช้งานโดยใช้ตัวดัดแปลงการเข้าถึง โดยใช้ getters และ setters สิ่งนี้ทำเพื่อปิดการเข้าถึงสำหรับการใช้งานภายนอกในสถานที่ที่นักพัฒนาเห็นว่าจำเป็น ตัวอย่างที่สามารถเข้าถึงได้จากชีวิตคือรถยนต์ เราไม่สามารถเข้าถึงการทำงานของเครื่องยนต์ได้โดยตรง สำหรับเรา งานคือการใส่กุญแจสตาร์ทเครื่องแล้วสตาร์ทเครื่องยนต์ และกระบวนการใดที่จะเกิดขึ้นภายใต้ประทุนนั้นไม่ใช่เรื่องของเรา ยิ่งกว่านั้น การแทรกแซงของเราในกิจกรรมนี้อาจนำไปสู่สถานการณ์ที่คาดเดาไม่ได้ ซึ่งทำให้รถพังและทำร้ายตัวเองได้ สิ่งเดียวกันนี้เกิดขึ้นในการเขียนโปรแกรม อธิบายไว้อย่าง ดีในวิกิพีเดีย นอกจากนี้ยังมีบทความเกี่ยวกับการห่อหุ้มบน JavaRush

4. ความหลากหลายคืออะไร?

ความแตกต่างคือความสามารถของโปรแกรมในการใช้วัตถุที่มีอินเทอร์เฟซเดียวกันเหมือนกันโดยไม่มีข้อมูลเกี่ยวกับประเภทเฉพาะของวัตถุนั้น อย่างที่พวกเขาพูดกันว่าอินเทอร์เฟซเดียว - การใช้งานหลายอย่าง ด้วยความหลากหลาย คุณสามารถรวมและใช้วัตถุประเภทต่างๆ ตามพฤติกรรมทั่วไปได้ ตัวอย่างเช่น เรามีคลาส Animal ซึ่งมีลูกหลานสองคน - สุนัขและแมว คลาสสัตว์ทั่วไปมีพฤติกรรมเหมือนกันสำหรับทุกคน - ส่งเสียง ในกรณีที่เราจำเป็นต้องรวบรวมลูกหลานทั้งหมดของคลาส Animal และดำเนินการวิธี "สร้างเสียง" เราจะใช้ความเป็นไปได้ของความหลากหลาย นี่คือสิ่งที่จะมีลักษณะดังนี้:
List<Animal> animals = Arrays.asList(new Cat(), new Dog(), new Cat());
animals.forEach(animal -> animal.makeSound());
ความหลากหลายจึงช่วยเราได้ นอกจากนี้ยังใช้กับวิธี polymorphic (โอเวอร์โหลด) อีกด้วย การฝึกใช้ความหลากหลาย

คำถามสัมภาษณ์ - ไวยากรณ์ Java

5. Constructor ใน Java คืออะไร?

ลักษณะต่อไปนี้ถูกต้อง:
  1. เมื่อมีการสร้างออบเจ็กต์ใหม่ โปรแกรมจะใช้ตัวสร้างที่เหมาะสมในการดำเนินการดังกล่าว
  2. ตัวสร้างก็เหมือนกับวิธีการ ลักษณะเฉพาะของมันคือไม่มีองค์ประกอบที่ส่งคืน (รวมถึงโมฆะ) และชื่อของมันก็เหมือนกับชื่อของคลาส
  3. หากไม่มีการเขียน Constructor อย่างชัดเจน Constructor ว่างจะถูกสร้างขึ้นโดยอัตโนมัติ
  4. ตัวสร้างสามารถแทนที่ได้
  5. หากมีการสร้างตัวสร้างที่มีพารามิเตอร์ แต่คุณจำเป็นต้องมีตัวสร้างที่ไม่มีพารามิเตอร์ด้วย คุณจะต้องเขียนแยกต่างหาก เนื่องจากไม่ได้ถูกสร้างขึ้นโดยอัตโนมัติ

6. สองคลาสใดที่ไม่สืบทอดมาจาก Object?

อย่าหลงกลโดยการยั่วยุ ไม่มีคลาสดังกล่าว: คลาสทั้งหมดโดยตรงหรือผ่านบรรพบุรุษได้รับการสืบทอดจากคลาส Object!

7. ตัวแปรท้องถิ่นคืออะไร?

อีกคำถามยอดนิยมระหว่างการสัมภาษณ์นักพัฒนา Java ตัวแปรท้องถิ่นคือตัวแปรที่กำหนดไว้ภายในวิธีการและมีอยู่จนกระทั่งวินาทีที่วิธีการถูกดำเนินการ เมื่อการดำเนินการสิ้นสุดลง ตัวแปรภายในเครื่องก็จะยุติลง นี่คือโปรแกรมที่ใช้ตัวแปรท้องถิ่น helloMessage ในเมธอด main():
public static void main(String[] args) {
   String helloMessage;
   helloMessage = "Hello, World!";
   System.out.println(helloMessage);
}

8. ตัวแปรอินสแตนซ์คืออะไร?

ตัวแปรอินสแตนซ์เป็นตัวแปรที่กำหนดไว้ภายในคลาสและจะมีอยู่จนกระทั่งถึงช่วงเวลาที่วัตถุมีอยู่ ตัวอย่างคือคลาส Bee ซึ่งมีตัวแปรสองตัว NectarCapacity และ maxNectarCapacity:
public class Bee {

   /**
    * Current nectar capacity
    */
   private double nectarCapacity;

   /**
    * Maximal nectar that can take bee.
    */
   private double maxNectarCapacity = 20.0;

  ...
}

9. ตัวแก้ไขการเข้าถึงคืออะไร?

ตัวแก้ไขการเข้าถึงเป็นเครื่องมือที่ช่วยให้คุณปรับแต่งการเข้าถึงคลาส วิธีการ และตัวแปรได้ มีตัวแก้ไขต่อไปนี้ เรียงลำดับเพื่อเพิ่มการเข้าถึง:
  1. private- ใช้สำหรับเมธอด ฟิลด์ และคอนสตรัคเตอร์ ระดับการเข้าถึงเป็นเพียงคลาสที่มีการประกาศเท่านั้น
  2. package-private(default)- สามารถใช้เรียนได้ เข้าถึงเฉพาะในแพ็คเกจเฉพาะที่มีการประกาศคลาส วิธีการ ตัวแปร ตัวสร้าง
  3. protected— การเข้าถึงแบบเดียวกับpackage-private+ สำหรับคลาสที่สืบทอดมาจากคลาสที่มีตัวprotectedดัดแปลง
  4. public- ใช้สำหรับชั้นเรียนด้วย สิทธิ์เข้าถึงแบบเต็มตลอดทั้งแอปพลิเคชัน
  5. คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 2

10. วิธีการเอาชนะคืออะไร?

การแทนที่เมธอดเกิดขึ้นเมื่อลูกต้องการเปลี่ยนพฤติกรรมของคลาสพาเรนต์ หากคุณต้องการให้สิ่งที่อยู่ในวิธีหลักถูกดำเนินการ คุณสามารถใช้โครงสร้างเช่น super.methodName() ในลูกได้ ซึ่งจะทำงานตามวิธีหลัก จากนั้นจึงเพิ่มตรรกะเท่านั้น ข้อกำหนดที่จะต้องปฏิบัติตาม:
  • ลายเซ็นวิธีการจะต้องเหมือนกัน
  • ค่าที่ส่งคืนควรเหมือนกัน

11. ลายเซ็นวิธีการคืออะไร?

คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 3ลายเซ็นวิธีการคือชุดของชื่อของวิธีการและอาร์กิวเมนต์ที่วิธีการยอมรับ ลายเซ็นวิธีการเป็นตัวระบุเฉพาะสำหรับวิธีการเมื่อวิธีการโอเวอร์โหลด

12. วิธีการโอเวอร์โหลดคืออะไร?

การโอเวอร์โหลดเมธอดเป็นคุณสมบัติของความหลากหลาย ซึ่งโดยการเปลี่ยนลายเซ็นเมธอด คุณสามารถสร้างวิธีการต่างๆ สำหรับการดำเนินการเดียวกันได้:
  • ชื่อวิธีเดียวกัน
  • ข้อโต้แย้งที่แตกต่างกัน
  • อาจมีประเภทการคืนสินค้าที่แตกต่างกัน
ตัวอย่างเช่น เดียวกันadd()ของArrayListสามารถโอเวอร์โหลดได้ดังต่อไปนี้ และจะดำเนินการเพิ่มในลักษณะที่แตกต่างกัน ขึ้นอยู่กับอาร์กิวเมนต์ที่เข้ามา:
  • add(Object o)- เพียงเพิ่มวัตถุ
  • add(int index, Object o)— เพิ่มวัตถุให้กับดัชนีเฉพาะ
  • add(Collection<Object> c)— เพิ่มรายการวัตถุ;
  • add(int index, Collection<Object> c)— เพิ่มรายการวัตถุโดยเริ่มจากดัชนีที่กำหนด

13. อินเทอร์เฟซคืออะไร?

การสืบทอดหลายรายการไม่ได้ถูกนำมาใช้ใน Java ดังนั้นเพื่อแก้ไขปัญหานี้ จึงมีการเพิ่มอินเทอร์เฟซตามที่เราทราบ ;) เป็นเวลานานแล้วที่อินเทอร์เฟซมีเพียงวิธีการที่ไม่ใช้งานเท่านั้น ส่วนหนึ่งของคำตอบนี้ เราจะพูดถึงพวกเขา ตัวอย่างเช่น:

public interface Animal {
   void makeSound();
   void eat();
   void sleep();
}
ความแตกต่างบางประการตามมาจากนี้:
  • วิธีการทั้งหมดในอินเทอร์เฟซเป็นแบบสาธารณะและเป็นนามธรรม
  • ตัวแปรทั้งหมดเป็นแบบคงที่สาธารณะขั้นสุดท้าย
  • คลาสไม่ได้รับการสืบทอด (ขยาย) แต่นำไปใช้ (นำไปใช้) นอกจากนี้คุณยังสามารถใช้อินเทอร์เฟซได้มากเท่าที่คุณต้องการ
  • คลาสที่ใช้อินเทอร์เฟซจะต้องจัดเตรียมการใช้งานของวิธีการทั้งหมดที่อินเทอร์เฟซมี
แบบนี้:
public class Cat implements Animal {
   public void makeSound() {
       // method implementation
   }

   public void eat() {
       // implementation
   }

   public void sleep() {
       // implementation
   }
}

14. วิธีการเริ่มต้นในอินเทอร์เฟซคืออะไร?

ตอนนี้เรามาพูดถึงวิธีการเริ่มต้นกัน เพื่ออะไร เพื่อใคร? วิธีการเหล่านี้ถูกเพิ่มเข้ามาเพื่อทำให้ทุกอย่าง “ทั้งของคุณและเรา” ฉันกำลังพูดถึงอะไร? ใช่ในอีกด้านหนึ่งจำเป็นต้องเพิ่มฟังก์ชันการทำงานใหม่: lambdas, Stream API ในทางกลับกันจำเป็นต้องละทิ้งสิ่งที่ Java มีชื่อเสียงในเรื่อง - ความเข้ากันได้แบบย้อนหลัง ในการทำเช่นนี้จำเป็นต้องแนะนำโซลูชันสำเร็จรูปให้กับอินเทอร์เฟซ นี่คือวิธีที่วิธีการเริ่มต้นมาถึงเรา นั่นคือวิธีการเริ่มต้นคือวิธีการนำไปใช้ในอินเทอร์เฟซที่มีคำdefaultหลัก ตัวอย่างเช่น วิธีการที่รู้จักกันดีstream()ในCollection. ลองดูสิ อินเทอร์เฟซนี้ไม่ง่ายอย่างที่คิด ;) หรือวิธีการที่รู้จักกันดีไม่แพ้กันforEach()จากIterable. ยังไม่มีอยู่จนกว่าจะมีการเพิ่มวิธีการเริ่มต้น อย่างไรก็ตาม คุณสามารถอ่านเกี่ยวกับเรื่องนี้ได้ใน JavaRush

15. แล้วจะสืบทอดวิธีการเริ่มต้นที่เหมือนกันสองวิธีได้อย่างไร?

จากคำตอบก่อนหน้านี้เกี่ยวกับวิธีการเริ่มต้น คุณสามารถถามคำถามอื่นได้ หากคุณสามารถนำวิธีการไปใช้ในส่วนต่อประสานได้ ตามทฤษฎีแล้วคุณสามารถใช้สองส่วนต่อประสานด้วยวิธีเดียวกันได้ และจะทำอย่างไร มีอินเทอร์เฟซที่แตกต่างกันสองแบบโดยใช้วิธีการเดียวกัน:
interface A {
   default void foo() {
       System.out.println("Foo A");
   }
}

interface B {
   default void foo() {
       System.out.println("Foo B");
   }
}
และมีคลาสที่ใช้อินเทอร์เฟซทั้งสองนี้ เพื่อหลีกเลี่ยงความไม่แน่นอนและเพื่อคอมไพล์โค้ด เราจำเป็นต้องแทนที่เมธอดfoo()ในคลาสCและเราสามารถเรียกเมธอดfoo()ของอินเทอร์เฟซใดๆ ในนั้น- Aหรือ Bแต่จะเลือกวิธีอินเทอร์เฟซเฉพาะได้อย่างไรАหรือВ? มีโครงสร้างเช่นนี้สำหรับสิ่งนี้A.super.foo():
public class C implements A, B {
   @Override
   public void foo() {
       A.super.foo();
   }
}
หรือ:
public class C implements A, B {
   @Override
   public void foo() {
       B.super.foo();
   }
}
ดังนั้น วิธี foo()การเรียนCจะใช้วิธีเริ่มต้นfoo()จากอินเทอร์เฟซAหรือวิธีการfoo()จากอินเทอร์เฟB

16. วิธีการและคลาสนามธรรมคืออะไร?

Java มีคำสงวนabstractที่ใช้เพื่อแสดงถึงคลาสและวิธีการที่เป็นนามธรรม ขั้นแรกให้คำจำกัดความบางประการ วิธีการแบบนามธรรมคือวิธีการที่สร้างขึ้นโดยไม่มีการใช้งานกับคำหลักabstractในคลาสนามธรรม นั่นคือนี่เป็นวิธีการเหมือนในอินเทอร์เฟซ เพียงเพิ่มคำหลักเท่านั้น เช่น:
public abstract void foo();
คลาสนามธรรมคือคลาสที่มีabstractคำว่า:
public abstract class A {

}
คลาสนามธรรมมีคุณสมบัติหลายประการ:
  • ไม่สามารถสร้างวัตถุบนพื้นฐานของมันได้
  • สามารถมีวิธีการเชิงนามธรรมได้
  • อาจไม่มีวิธีการเชิงนามธรรม
จำเป็นต้องมีคลาสนามธรรมเพื่อสรุปนามธรรมบางประเภท (ขออภัยที่ซ้ำซาก) ซึ่งไม่มีอยู่จริงในชีวิตจริง แต่มีพฤติกรรมและสถานะทั่วไปหลายอย่าง (นั่นคือ วิธีการและตัวแปร) มีตัวอย่างจากชีวิตมากมายเกินพอ ทุกสิ่งอยู่รอบตัวเรา อาจเป็น "สัตว์" "รถยนต์" "รูปทรงเรขาคณิต" และอื่นๆ

17. อะไรคือความแตกต่างระหว่าง String, String Builder และ String Buffer?

ค่าStringจะถูกเก็บไว้ในพูลสตริงคงที่ เมื่อสร้างแถวแล้ว แถวนั้นจะปรากฏในกลุ่มนี้ และจะไม่สามารถลบออกได้ ตัวอย่างเช่น:
String name = "book";
...ตัวแปรจะอ้างอิงถึงพูลสตริง พูลสตริงคงที่ คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 4 หากคุณตั้งชื่อตัวแปรเป็นค่าอื่น คุณจะได้รับสิ่งต่อไปนี้:
name = "pen";
พูลสตริงคงที่ คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 5ดังนั้นทั้งสองค่านี้จะยังคงอยู่ตรงนั้น บัฟเฟอร์สตริง:
  • ค่าStringจะถูกเก็บไว้ในสแต็ก หากค่ามีการเปลี่ยนแปลง ค่าใหม่จะถูกแทนที่ด้วยค่าเก่า
  • String Bufferซิงโครไนซ์และปลอดภัยต่อเธรด
  • เนื่องจากความปลอดภัยของเกลียว ความเร็วในการทำงานจึงเป็นที่ต้องการอย่างมาก
ตัวอย่าง:
StringBuffer name = "book";
คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 6ทันทีที่ค่าของชื่อเปลี่ยนแปลง ค่าบนสแต็กจะเปลี่ยน: คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ตอนที่ 1 - 7StringBuilder เหมือนกับ อย่างเดียวStringBufferเท่านั้นที่ไม่ปลอดภัยสำหรับเธรด ดังนั้นความเร็วของมันจึงสูงกว่าในStringBuffer.

18. อะไรคือความแตกต่างระหว่างคลาสนามธรรมและอินเทอร์เฟซ?

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

19. เหตุใดการเข้าถึงองค์ประกอบในอาเรย์จึงต้องใช้ O(1)

คำถามนี้มาจากการสัมภาษณ์ครั้งล่าสุด ตามที่ฉันได้เรียนรู้ในภายหลัง มีการถามคำถามนี้เพื่อดูว่าบุคคลคิดอย่างไร เห็นได้ชัดว่าความรู้นี้มีความหมายเชิงปฏิบัติเพียงเล็กน้อย แค่รู้ข้อเท็จจริงนี้ก็เพียงพอแล้ว อันดับแรก เราต้องชี้แจงว่า O(1) เป็นการกำหนดความซับซ้อนของเวลาของอัลกอริทึมเมื่อการดำเนินการเกิดขึ้นในเวลาคงที่ นั่นคือการกำหนดนี้เป็นการดำเนินการที่เร็วที่สุด เพื่อตอบคำถามนี้ เราต้องเข้าใจสิ่งที่เรารู้เกี่ยวกับอาร์เรย์? ในการสร้างอาร์เรย์intเราต้องเขียนดังต่อไปนี้:
int[] intArray = new int[100];
สามารถสรุปได้หลายประการจากบันทึกนี้:
  1. เมื่อสร้างอาร์เรย์ จะทราบประเภทของอาร์เรย์ หากทราบประเภท จะชัดเจนว่าแต่ละเซลล์ของอาร์เรย์จะมีขนาดเท่าใด
  2. เป็นที่ทราบกันว่าอาร์เรย์จะมีขนาดเท่าใด
จากนี้ไป: เพื่อทำความเข้าใจว่าเซลล์ใดที่จะเขียน คุณเพียงแค่ต้องคำนวณพื้นที่หน่วยความจำที่จะเขียน สำหรับรถยนต์มันไม่ง่ายไปกว่านี้อีกแล้ว เครื่องมีการเริ่มต้นของหน่วยความจำที่จัดสรร องค์ประกอบจำนวนหนึ่ง และขนาดเซลล์เดียว จากนี้เห็นได้ชัดว่าพื้นที่บันทึกจะเท่ากับตำแหน่งเริ่มต้นของอาร์เรย์ + ขนาดของเซลล์คูณด้วยขนาดของมัน

คุณจะได้รับ O (1) เข้าถึงวัตถุใน ArrayList ได้อย่างไร

คำถามนี้ตามหลังคำถามก่อนหน้าทันที เป็นความจริงที่ว่าเมื่อเราทำงานกับอาร์เรย์และมีพื้นฐานอยู่ที่นั่น เรารู้ล่วงหน้าว่าประเภทของประเภทนี้คือเท่าใดเมื่อสร้างขึ้น แต่จะเกิดอะไรขึ้นถ้ามีรูปแบบเหมือนในภาพ: คำถามและคำตอบสัมภาษณ์ Java Core 50 อันดับแรก  ส่วนที่ 1 - 8และเราต้องการสร้างคอลเลกชันที่มีองค์ประกอบประเภท A และเพิ่มการใช้งานที่แตกต่างกัน - B, C, D:
List<A> list = new ArrayList();
list.add(new B());
list.add(new C());
list.add(new D());
list.add(new B());
ในสถานการณ์เช่นนี้ คุณจะเข้าใจได้อย่างไรว่าแต่ละเซลล์จะมีขนาดเท่าใด เนื่องจากแต่ละวัตถุจะแตกต่างกันและอาจมีฟิลด์เพิ่มเติมที่แตกต่างกัน (หรือแตกต่างกันโดยสิ้นเชิง) จะทำอย่างไร? ในที่นี้มีการตั้งคำถามในลักษณะที่ทำให้สับสนและสับสน เรารู้ว่าในความเป็นจริงแล้ว คอลเลกชันไม่ได้จัดเก็บวัตถุ แต่ลิงก์ไปยังวัตถุเหล่านี้เท่านั้น และลิงค์ทั้งหมดมีขนาดเท่ากันและเป็นที่รู้จัก ดังนั้นการนับพื้นที่ตรงนี้จึงใช้วิธีเดียวกับคำถามที่แล้ว

21. การทำกล่องอัตโนมัติและการแกะกล่อง

ภูมิหลังในอดีต: autoboxing และ autounboxing เป็นหนึ่งในนวัตกรรมหลักของ JDK 5 Autoboxingเป็นกระบวนการของการแปลงอัตโนมัติจากประเภทดั้งเดิมไปเป็นคลาส wrapper ที่เหมาะสม Auto-unboxing - ทำสิ่งที่ตรงกันข้ามกับ auto-boxing ทุกประการ - แปลงคลาส wrapper ให้เป็นคลาสดั้งเดิม แต่ถ้ามีค่า wrapper nullก็จะมีข้อยกเว้นเกิดขึ้นระหว่างการคลายNullPointerExceptionแพ็ก

การจับคู่ดั้งเดิม - wrapper

ดั้งเดิม กระดาษห่อชั้นเรียน
บูลีน บูลีน
ภายใน จำนวนเต็ม
ไบต์ ไบต์
ถ่าน อักขระ
ลอย ลอย
ยาว ยาว
สั้น สั้น
สองเท่า สองเท่า

การบรรจุอัตโนมัติเกิดขึ้น:

  • เมื่อกำหนดการอ้างอิงดั้งเดิมให้กับคลาส wrapper:

    ก่อนจาวา 5:

    //manual packaging or how it was BEFORE Java 5.
    public void boxingBeforeJava5() {
       Boolean booleanBox = new Boolean(true);
       Integer intBox = new Integer(3);
       // and so on to other types
    }
    
    после Java 5:
    //automatic packaging or how it became in Java 5.
    public void boxingJava5() {
       Boolean booleanBox = true;
       Integer intBox = 3;
       // and so on to other types
    }
  • เมื่อส่งผ่านดั้งเดิมเป็นอาร์กิวเมนต์ไปยังวิธีการที่คาดหวัง wrapper:

    public void exampleOfAutoboxing() {
       long age = 3;
       setAge(age);
    }
    
    public void setAge(Long age) {
       this.age = age;
    }

การแกะกล่องอัตโนมัติเกิดขึ้น:

  • เมื่อเรากำหนดตัวแปรดั้งเดิมให้กับคลาส wrapper:

    //before Java 5:
    int intValue = new Integer(4).intValue();
    double doubleValue = new Double(2.3).doubleValue();
    char c = new Character((char) 3).charValue();
    boolean b = Boolean.TRUE.booleanValue();
    
    //and after JDK 5:
    int intValue = new Integer(4);
    double doubleValue = new Double(2.3);
    char c = new Character((char) 3);
    boolean b = Boolean.TRUE;
  • ในกรณีที่มีการดำเนินการทางคณิตศาสตร์ ใช้กับประเภทดั้งเดิมเท่านั้นสำหรับสิ่งนี้คุณต้องทำการแกะออกจากประเภทดั้งเดิม

    // Before Java 5
    Integer integerBox1 = new Integer(1);
    Integer integerBox2 = new Integer(2);
    
    // for comparison it was necessary to do this:
    integerBox1.intValue() > integerBox2.intValue()
    
    //в Java 5
    integerBox1 > integerBox2
  • เมื่อส่งผ่านไปยัง wrapper ด้วยวิธีการที่ยอมรับค่าพื้นฐานที่เกี่ยวข้อง:

    public void exampleOfAutoboxing() {
       Long age = new Long(3);
       setAge(age);
    }
    
    public void setAge(long age) {
       this.age = age;
    }

22. คำสำคัญสุดท้ายคืออะไร และจะใช้ได้ที่ไหน?

คำสำคัญfinalสามารถใช้กับตัวแปร วิธีการ และคลาสได้
  1. ตัวแปรสุดท้ายไม่สามารถกำหนดใหม่ให้กับวัตถุอื่นได้
  2. ชั้นสุดท้ายเป็นหมัน)) ไม่สามารถมีทายาทได้
  3. วิธีสุดท้ายไม่สามารถแทนที่บนบรรพบุรุษได้
เราได้พูดถึงเรื่องด้านบนแล้ว ตอนนี้เรามาพูดคุยกันในรายละเอียดเพิ่มเติมกันดีกว่า

ตัวแปรสุดท้าย

;Java ให้สองวิธีในการสร้างตัวแปรและกำหนดค่าให้กับมัน:
  1. คุณสามารถประกาศตัวแปรและเริ่มต้นได้ในภายหลัง
  2. คุณสามารถประกาศตัวแปรและกำหนดได้ทันที
ตัวอย่างการใช้ตัวแปรสุดท้ายสำหรับกรณีเหล่านี้:
public class FinalExample {

   //final static variable, which is immediately initialized:
   final static String FINAL_EXAMPLE_NAME = "I'm likely final one";

   //final is a variable that is not initialized, but will only work if
   //initialize this in the constructor:
   final long creationTime;

   public FinalExample() {
       this.creationTime = System.currentTimeMillis();
   }

   public static void main(String[] args) {
       FinalExample finalExample = new FinalExample();
       System.out.println(finalExample.creationTime);

       // final field FinalExample.FINAL_EXAMPLE_NAME cannot be assigned
//    FinalExample.FINAL_EXAMPLE_NAME = "Not you're not!";

       // final field Config.creationTime cannot be assigned
//    finalExample.creationTime = 1L;
   }
}

ตัวแปรสุดท้ายสามารถถือเป็นค่าคงที่ได้หรือไม่?

เนื่องจากเราไม่สามารถกำหนดค่าใหม่ให้กับตัวแปรสุดท้ายได้ จึงดูเหมือนว่าตัวแปรเหล่านี้เป็นตัวแปรคงที่ แต่นี่เป็นเพียงการมองแวบแรกเท่านั้น หากประเภทข้อมูลที่ตัวแปรอ้างถึงคือ immutableใช่ มันเป็นค่าคงที่ แต่ถ้าชนิดข้อมูลmutableไม่แน่นอน การใช้เมธอดและตัวแปร จะสามารถเปลี่ยนค่าของออบเจ็กต์ที่finalตัวแปรอ้างอิงถึงได้ และในกรณีนี้จะเรียกว่าค่าคงที่ไม่ได้ จากตัวอย่างแสดงให้เห็นว่าตัวแปรสุดท้ายบางตัวมีค่าคงที่จริงๆ แต่บางตัวไม่เป็นค่าคงที่ และสามารถเปลี่ยนแปลงได้
public class FinalExample {

   //immutable final variables:
   final static String FINAL_EXAMPLE_NAME = "I'm likely final one";
   final static Integer FINAL_EXAMPLE_COUNT  = 10;

   // mutable filter variables
   final List<String> addresses = new ArrayList();
   final StringBuilder finalStringBuilder = new StringBuilder("constant?");
}

ตัวแปรสุดท้ายเฉพาะที่

เมื่อfinalตัวแปรถูกสร้างขึ้นภายในวิธีการ มันถูกเรียกว่าlocal finalตัวแปร:
public class FinalExample {

   public static void main(String[] args) {
       // This is how you can
       final int minAgeForDriveCar = 18;

       // or you can do it this way, in the foreach loop:
       for (final String arg : args) {
           System.out.println(arg);
       }
   }

}
เราสามารถใช้คีย์เวิร์ดfinalในการวนซ้ำแบบขยายได้forเพราะหลังจากการวนซ้ำเสร็จสิ้นแล้วforตัวแปรใหม่จะถูกสร้างขึ้นในแต่ละครั้ง แต่สิ่งนี้จะไม่มีผลกับ for loop ปกติ ดังนั้นโค้ดด้านล่างจะทำให้เกิดข้อผิดพลาดขณะคอมไพล์
// final local changed j cannot be assigned
for (final int i = 0; i < args.length; i ++) {
   System.out.println(args[i]);
}

ชั้นเรียนสุดท้าย

คุณไม่สามารถขยายคลาสที่ประกาศเป็นfinal. พูดง่ายๆ ก็คือ ไม่มีคลาสใดที่สามารถสืบทอดจากคลาสนี้ได้ ตัวอย่างที่ดีfinalของคลาสใน JDK คือString. ขั้นตอนแรกในการสร้างคลาสที่ไม่เปลี่ยนรูปคือการทำเครื่องหมายเป็นfinalเพื่อไม่ให้ขยายได้:
public final class FinalExample {
}

// Compilation error here
class WantsToInheritFinalClass extends FinalExample {
}

วิธีการสุดท้าย

เมื่อวิธีถูกทำเครื่องหมายเป็นขั้นสุดท้าย จะเรียกว่าวิธีสุดท้าย (ตรรกะใช่ไหม?) ไม่สามารถแทนที่วิธีการสุดท้ายในคลาสที่สืบทอดได้ อย่างไรก็ตาม วิธีการในคลาส Object - wait() และ notify() - ถือเป็นที่สิ้นสุด ดังนั้นเราจึงไม่มีโอกาสที่จะแทนที่วิธีการเหล่านั้น
public class FinalExample {
   public final String generateAddress() {
       return "Some address";
   }
}

class ChildOfFinalExample extends FinalExample {

   // compile error here
   @Override
   public String generateAddress() {
       return "My OWN Address";
   }
}

จะใช้ Final ใน Java อย่างไรและที่ไหน

  • ใช้คีย์เวิร์ดสุดท้ายเพื่อกำหนดค่าคงที่ระดับคลาส
  • สร้างตัวแปรสุดท้ายสำหรับวัตถุเมื่อคุณไม่ต้องการให้แก้ไข ตัวอย่างเช่น คุณสมบัติเฉพาะออบเจ็กต์ที่เราสามารถใช้เพื่อวัตถุประสงค์ในการบันทึก
  • หากคุณไม่ต้องการขยายชั้นเรียน ให้ทำเครื่องหมายว่าเป็นชั้นเรียนสุดท้าย
  • หากคุณต้องการสร้างคลาส < ที่ไม่เปลี่ยนรูป คุณจะต้องทำให้คลาสนั้นกลายเป็นขั้นสุดท้าย
  • หากคุณต้องการให้การนำเมธอดไปใช้ไม่เปลี่ยนแปลงในลูกหลาน ให้กำหนดเมธอดเป็นfinal. นี่เป็นสิ่งสำคัญมากเพื่อให้แน่ใจว่าการดำเนินการจะไม่เปลี่ยนแปลง

23. อะไรคือสิ่งที่ไม่แน่นอนและไม่เปลี่ยนรูป?

ไม่แน่นอน

การเปลี่ยนแปลงได้คือวัตถุที่สถานะและตัวแปรสามารถเปลี่ยนแปลงได้หลังจากการสร้าง ตัวอย่างเช่น คลาสต่างๆ เช่น StringBuilder, StringBuffer ตัวอย่าง:
public class MutableExample {

   private String address;

   public MutableExample(String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   // this setter can change the name field
   public void setAddress(String address) {
       this.address = address;
   }

   public static void main(String[] args) {

       MutableExample obj = new MutableExample("first address");
       System.out.println(obj.getAddress());

       // update the name field, so this is a mutable object
       obj.setAddress("Updated address");
       System.out.println(obj.getAddress());
   }
}

ไม่เปลี่ยนรูป

ไม่เปลี่ยนรูปคือวัตถุที่ไม่สามารถเปลี่ยนสถานะและตัวแปรได้หลังจากสร้างวัตถุแล้ว ทำไมไม่ใช่คีย์ที่ดีสำหรับ HashMap ใช่ไหม) ตัวอย่างเช่น String, Integer, Double และอื่นๆ ตัวอย่าง:
// make this class final so no one can change it
public final class ImmutableExample {

   private String address;

   ImmutableExample (String address) {
       this.address = address;
   }

   public String getAddress() {
       return address;
   }

   //remove the setter

   public static void main(String[] args) {

       ImmutableExample obj = new ImmutableExample("old address");
       System.out.println(obj.getAddress());

       // Therefore, do not change this field in any way, so this is an immutable object
       // obj.setName("new address");
       // System.out.println(obj.getName());

   }
}

24. จะเขียนคลาสที่ไม่เปลี่ยนรูปได้อย่างไร?

หลังจากที่คุณทราบว่าวัตถุที่ไม่เปลี่ยนรูปและไม่เปลี่ยนรูปคืออะไร คำถามต่อไปก็เป็นไปตามธรรมชาติ - จะเขียนมันได้อย่างไร? ในการเขียนคลาสที่ไม่เปลี่ยนรูปที่ไม่เปลี่ยนรูป คุณต้องทำตามขั้นตอนง่ายๆ:
  • ทำให้ชั้นเรียนเป็นอันสิ้นสุด
  • ทำให้ทุกฟิลด์เป็นแบบส่วนตัวและสร้างเฉพาะ getters สำหรับฟิลด์เหล่านั้น แน่นอนว่าไม่จำเป็นต้องใช้ผู้ตั้งค่า
  • ทำให้ฟิลด์ที่ไม่แน่นอนทั้งหมดเป็นขั้นสุดท้ายเพื่อให้สามารถตั้งค่าได้เพียงครั้งเดียว
  • เริ่มต้นฟิลด์ทั้งหมดผ่านตัวสร้าง ดำเนินการคัดลอกแบบลึก (นั่นคือ การคัดลอกออบเจ็กต์เอง ตัวแปร ตัวแปรของตัวแปร และอื่นๆ)
  • โคลนอ็อบเจ็กต์ตัวแปรที่ไม่แน่นอนใน getters เพื่อส่งคืนเฉพาะสำเนาของค่า ไม่ใช่การอ้างอิงไปยังอ็อบเจ็กต์จริง
ตัวอย่าง:
/**
* An example of creating an immutable object.
*/
public final class FinalClassExample {

   private final int age;

   private final String name;

   private final HashMap<String, String> addresses;

   public int getAge() {
       return age;
   }


   public String getName() {
       return name;
   }

   /**
    * Clone the object before returning it.
    */
   public HashMap<String, String> getAddresses() {
       return (HashMap<String, String>) addresses.clone();
   }

   /**
    * In the constructor, deep copy the mutable objects.
    */
   public FinalClassExample(int age, String name, HashMap<String, String> addresses) {
       System.out.println("Performing a deep copy in the constructor");
       this.age = age;
       this.name = name;
       HashMap<String, String> temporaryMap = new HashMap<>();
       String key;
       Iterator<String> iterator = addresses.keySet().iterator();
       while (iterator.hasNext()) {
           key = iterator.next();
           temporaryMap.put(key, addresses.get(key));
       }
       this.addresses = temporaryMap;
   }
}
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION