
กลาง
เป็นเรื่องธรรมดา
1. อะไรคือข้อดีและข้อเสียของ OOP เมื่อเปรียบเทียบกับการเขียนโปรแกรมตามขั้นตอน/ฟังก์ชัน
มีคำถามนี้ในการวิเคราะห์คำถามของรุ่นจูเนียร์ และด้วยเหตุนี้ ฉันก็ตอบไปแล้ว ค้นหาคำถามนี้และคำตอบใน ส่วน นี้ของบทความ คำถามที่ 16 และ 172. การรวมกลุ่มแตกต่างจากการจัดองค์ประกอบอย่างไร
ใน OOP มีการโต้ตอบระหว่างวัตถุหลายประเภท ซึ่งรวมกันภายใต้แนวคิดทั่วไปของ "ความสัมพันธ์แบบมี-แบบ" ความสัมพันธ์นี้บ่งชี้ว่าวัตถุหนึ่งเป็นส่วนประกอบของวัตถุอื่น ในขณะเดียวกัน ความสัมพันธ์นี้มีสองประเภทย่อย: องค์ประกอบ - วัตถุหนึ่งสร้างวัตถุอื่น และอายุการใช้งานของวัตถุอื่นขึ้นอยู่กับอายุการใช้งานของผู้สร้าง การรวมกลุ่ม - วัตถุได้รับลิงก์ (ตัวชี้) ไปยังวัตถุอื่นในระหว่างกระบวนการก่อสร้าง (ในกรณีนี้ อายุการใช้งานของวัตถุอื่นไม่ได้ขึ้นอยู่กับอายุการใช้งานของผู้สร้าง) เพื่อความเข้าใจที่ดีขึ้น เรามาดูตัวอย่างที่เฉพาะเจาะจงกัน เรามีคลาสรถยนต์บางประเภท - Carซึ่งจะมีฟิลด์ภายในประเภท - Engine และรายชื่อผู้โดยสาร - List<Passenger>แต่ก็มีวิธีการในการเริ่มการเคลื่อนที่ - startMoving() :public class Car {
private Engine engine;
private List<Passenger> passengers;
public Car(final List<Passenger> passengers) {
this.engine = new Engine();
this.passengers = passengers;
}
public void addPassenger(Passenger passenger) {
passengers.add(passenger);
}
public void removePassengerByIndex(Long index) {
passengers.remove(index);
}
public void startMoving() {
engine.start();
System.out.println("Машина начала своё движение");
for (Passenger passenger : passengers) {
System.out.println("В машине есть пассажир - " + passenger.getName());
}
}
}
ในกรณีนี้องค์ประกอบคือการเชื่อมต่อระหว่างCarและEngineเนื่องจากประสิทธิภาพของรถยนต์ขึ้นอยู่กับการมีอยู่ของวัตถุเครื่องยนต์โดยตรง เพราะถ้าengine = nullเราจะได้รับNullPointerException ในทางกลับกัน เครื่องยนต์ไม่สามารถดำรงอยู่ได้หากไม่มีเครื่องจักร (เหตุใดเราจึงต้องมีเครื่องยนต์ที่ไม่มีเครื่องจักร) และไม่สามารถเป็นของเครื่องจักรหลายเครื่องได้ในคราวเดียว ซึ่งหมายความว่าหากเราลบ วัตถุ Carจะไม่มีการอ้างอิง ถึง วัตถุEngine อีกต่อไป และใน ไม่ ช้า Garbage Collector ก็จะถูกลบทิ้ง อย่างที่คุณเห็นความสัมพันธ์นี้เข้มงวดมาก (แข็งแกร่ง) การรวมกลุ่มคือการเชื่อมโยงระหว่างรถยนต์และผู้โดยสารเนื่องจากประสิทธิภาพของรถยนต์ไม่ได้ขึ้นอยู่กับ ประเภท ผู้โดยสารและจำนวน ผู้โดยสารแต่อย่างใด พวกเขาสามารถออกจากรถ - ลบPassengerByIndex(ดัชนีแบบยาว)หรือป้อนใหม่ - addPassenger(ผู้โดยสารผู้โดยสาร)แม้ว่าจะเป็นเช่นนี้ รถจะยังคงทำงานได้อย่างถูกต้องต่อไป ในทางกลับกัน วัตถุ Passengerสามารถดำรงอยู่ได้โดยไม่มีวัตถุCar ดังที่คุณเข้าใจ นี่เป็นการเชื่อมต่อที่อ่อนแอกว่าที่เราเห็นในองค์ประกอบภาพมาก 
3. คุณใช้รูปแบบ GoF ใดในทางปฏิบัติ? ยกตัวอย่าง.
ฉันเคยตอบคำถามนี้ไปแล้ว ดังนั้นฉันจะทิ้งลิงก์ไปยังการวิเคราะห์ดูคำถามแรก ฉันยังพบบทความโกง ที่ยอดเยี่ยม เกี่ยวกับรูปแบบการออกแบบ ซึ่งฉันขอแนะนำอย่างยิ่งให้เก็บไว้4. อ็อบเจ็กต์พร็อกซีคืออะไร? ยกตัวอย่าง
พร็อกซีเป็นรูปแบบการออกแบบโครงสร้างที่ช่วยให้คุณสามารถทดแทนวัตถุทดแทนพิเศษ หรืออีกนัยหนึ่งคือวัตถุพร็อกซี แทนวัตถุจริง ออบเจ็กต์พร็อกซีเหล่านี้ดักฟังการเรียกไปยังออบเจ็กต์ต้นฉบับ ทำให้สามารถแทรกตรรกะบางอย่างก่อนหรือหลังการเรียกถูกส่งผ่านไปยังออบเจ็กต์ดั้งเดิม
-
เป็นพร็อกซีระยะไกล - ใช้เมื่อเราต้องการวัตถุระยะไกล (วัตถุในพื้นที่ที่อยู่อื่น) ที่จำเป็นต้องแสดงภายในเครื่อง ในกรณีนี้ พร็อกซีจะจัดการการสร้างการเชื่อมต่อ การเข้ารหัส การถอดรหัส ฯลฯ ในขณะที่ไคลเอ็นต์จะใช้พร็อกซีราวกับว่าเป็นวัตถุดั้งเดิมที่อยู่ในพื้นที่ท้องถิ่น
-
เป็นพร็อกซีเสมือน - ใช้เมื่อต้องการออบเจ็กต์ที่ใช้ทรัพยากรมาก ในกรณีนี้ อ็อบเจ็กต์พร็อกซีจะทำหน้าที่เป็นรูปภาพของวัตถุจริงที่ยังไม่มีอยู่จริง เมื่อคำขอจริง (การเรียกเมธอด) ถูกส่งไปยังออบเจ็กต์นี้ เฉพาะออบเจ็กต์ต้นฉบับเท่านั้นที่โหลดและวิธีการดำเนินการ วิธีการนี้เรียกอีกอย่างว่าการเริ่มต้นแบบ Lazy ซึ่งจะสะดวกมาก เพราะในบางสถานการณ์ ออบเจ็กต์ต้นฉบับอาจไม่มีประโยชน์ และจะไม่มีค่าใช้จ่ายในการสร้างมัน
-
เป็นพร็อกซีความปลอดภัย - ใช้เมื่อคุณต้องการควบคุมการเข้าถึงออบเจ็กต์บางอย่างตามสิทธิ์ของไคลเอ็นต์ นั่นคือ หากไคลเอ็นต์ที่ไม่มีสิทธิ์การเข้าถึงพยายามเข้าถึงออบเจ็กต์ดั้งเดิม พร็อกซีจะดักจับและไม่อนุญาต
public interface Processor {
void process();
}
การใช้งานซึ่งใช้ทรัพยากรมากเกินไป แต่ในขณะเดียวกันก็อาจไม่สามารถใช้ได้ทุกครั้งที่เปิดตัวแอปพลิเคชัน:
public class HiperDifficultProcessor implements Processor {
@Override
public void process() {
// некоторый сверхсложная обработка данных
}
}
คลาสพร็อกซี:
public class HiperDifficultProcessorProxy implements Processor {
private HiperDifficultProcessor processor;
@Override
public void process() {
if (processor == null) {
processor = new HiperDifficultProcessor();
}
processor.process();
}
}
มารันกันที่main :
Processor processor = new HiperDifficultProcessorProxy();
// тут тяжеловсеного оригинального an object, ещё не сущетсвует
// но при этом есть an object, который его представляет и у которого можно вызывать его методы
processor.process(); // лишь теперь, an object оригинал был создан
ฉันทราบว่าเฟรมเวิร์กจำนวนมากใช้การพร็อกซี และสำหรับSpringนี่เป็นรูปแบบที่สำคัญ (Spring ถูกเย็บเข้าและออก) อ่านเพิ่มเติมเกี่ยวกับรูปแบบนี้ได้ที่นี่ 
5. มีการประกาศนวัตกรรมอะไรบ้างใน Java 8?
นวัตกรรมที่นำโดย Java 8 มีดังนี้:-
เพิ่มอินเทอร์เฟซการใช้งานแล้ว อ่านเกี่ยวกับสัตว์ร้ายชนิดนี้ได้ที่นี่
-
นิพจน์ Lambda ซึ่งเกี่ยวข้องอย่างใกล้ชิดกับอินเทอร์เฟซการทำงาน อ่านเพิ่มเติมเกี่ยวกับการใช้งานได้ที่นี่
-
เพิ่มStream APIเพื่อการประมวลผลการรวบรวมข้อมูลที่สะดวก อ่านเพิ่มเติมที่นี่
-
เพิ่มลิงค์ไปยังวิธีการ
-
เพิ่มเมธอดforEach()ให้กับ อินเทอร์เฟซ Iterableแล้ว
-
เพิ่มAPI วันที่และเวลา ใหม่ใน แพ็คเกจ java.timeการวิเคราะห์โดยละเอียดที่นี่
-
ปรับปรุงAPI ที่เกิดขึ้นพร้อมกัน
-
เมื่อเพิ่ม คลาส wrapper เสริม ซึ่งใช้เพื่อจัดการค่า Null อย่างถูก ต้องคุณสามารถค้นหาบทความดีๆ เกี่ยวกับหัวข้อนี้ได้ที่นี่
-
การเพิ่มความสามารถสำหรับอินเทอร์เฟซในการใช้ วิธี คงที่และเริ่มต้น (ซึ่งโดยพื้นฐานแล้วทำให้ Java เข้าใกล้การสืบทอดหลายรายการมากขึ้น) รายละเอียดเพิ่มเติมที่นี่
-
เพิ่มวิธีการใหม่ให้กับคลาสCollection(removeIf(), spliterator())
-
การปรับปรุงเล็กน้อยใน Java Core

6. การยึดเกาะสูงและการเชื่อมต่อต่ำคืออะไร? ยกตัวอย่าง.
High CohesionหรือHigh Cohesionเป็นแนวคิดเมื่อคลาสบางคลาสมีองค์ประกอบที่เกี่ยวข้องกันอย่างใกล้ชิดและรวมกันเพื่อจุดประสงค์ของมัน ตัวอย่างเช่น วิธีการทั้งหมดใน คลาส Userควรแสดงถึงพฤติกรรมของผู้ใช้ คลาสมีการทำงานร่วมกันต่ำหากมีองค์ประกอบที่ไม่เกี่ยวข้องกัน ตัวอย่างเช่น คลาส Userที่มีวิธีการตรวจสอบที่อยู่อีเมล:public class User {
private String name;
private String email;
public String getName() {
return this.name;
}
public void setName(final String name) {
this.name = name;
}
public String getEmail() {
return this.email;
}
public void setEmail(final String email) {
this.email = email;
}
public boolean isValidEmail() {
// некоторая логика валидации емейла
}
}
คลาสผู้ใช้อาจรับผิดชอบในการจัดเก็บที่อยู่อีเมลของผู้ใช้ แต่ไม่ใช่สำหรับการตรวจสอบความถูกต้องหรือส่งอีเมล ดังนั้น เพื่อให้เกิดการเชื่อมโยงกันในระดับสูง เราจึงย้ายวิธีการตรวจสอบความถูกต้องไปไว้ในคลาสยูทิลิตี้ที่แยกจากกัน:
public class EmailUtil {
public static boolean isValidEmail(String email) {
// некоторая логика валидации емейла
}
}
และเราใช้ตามความจำเป็น (เช่น ก่อนบันทึกผู้ใช้) ข้อต่อต่ำหรือข้อต่อต่ำเป็นแนวคิดที่อธิบายการพึ่งพาอาศัยกันต่ำระหว่างโมดูลซอฟต์แวร์ โดยพื้นฐานแล้ว การพึ่งพาซึ่งกันและกันคือการเปลี่ยนแปลงสิ่งหนึ่งซึ่งต้องเปลี่ยนอีกสิ่งหนึ่ง สองชั้นมีการมีเพศสัมพันธ์ที่แข็งแกร่ง (หรือการมีเพศสัมพันธ์ที่แน่นหนา) หากมีความสัมพันธ์กันอย่างใกล้ชิด ตัวอย่างเช่น คลาสที่เป็นรูปธรรมสองคลาสที่เก็บการอ้างอิงถึงกันและเรียกเมธอดของกันและกัน คลาสคู่ที่หลวมจะพัฒนาและบำรุงรักษาได้ง่ายกว่า เนื่องจากเป็นอิสระจากกัน จึงสามารถพัฒนาและทดสอบแบบคู่ขนานได้ นอกจากนี้ยังสามารถเปลี่ยนแปลงและปรับปรุงได้โดยไม่กระทบต่อกัน ลองดูตัวอย่างของคลาสที่เชื่อมโยงกันอย่างแน่นหนา เรามีชั้นเรียนของนักเรียน:
public class Student {
private Long id;
private String name;
private List<Lesson> lesson;
}
ซึ่งมีรายการบทเรียน:
public class Lesson {
private Long id;
private String name;
private List<Student> students;
}
แต่ละบทเรียนมีลิงก์ไปยังนักเรียนที่เข้าร่วม ด้ามจับที่แข็งแกร่งอย่างไม่น่าเชื่อ คุณว่าไหม? คุณจะลดมันได้อย่างไร? ขั้นแรก ตรวจสอบให้แน่ใจว่านักเรียนไม่มีรายชื่อวิชา แต่เป็นรายชื่อตัวระบุ:
public class Student {
private Long id;
private String name;
private List<Long> lessonIds;
}
ประการที่สอง ชั้นเรียนไม่จำเป็นต้องรู้เกี่ยวกับนักเรียนทุกคน ดังนั้นให้ลบรายชื่อนักเรียนทั้งหมดเลย:
public class Lesson {
private Long id;
private String name;
}
ดังนั้นมันจึงง่ายขึ้นมาก และการเชื่อมต่อก็อ่อนแอลงมาก คุณว่ามั้ย? 
อุ๊ย
7. คุณจะใช้การสืบทอดหลายรายการใน Java ได้อย่างไร?
การสืบทอดหลายรายการเป็นคุณลักษณะของแนวคิดเชิงวัตถุซึ่งคลาสสามารถสืบทอดคุณสมบัติจากคลาสพาเรนต์มากกว่าหนึ่งคลาส ปัญหาเกิดขึ้นเมื่อมีเมธอดที่มีลายเซ็นเหมือนกันทั้งในคลาสซุปเปอร์และคลาสย่อย เมื่อเรียกเมธอด คอมไพลเลอร์ไม่สามารถระบุได้ว่าควรเรียกเมธอดคลาสใด และแม้แต่เมื่อเรียกเมธอดคลาสที่มีความสำคัญกว่าก็ตาม ดังนั้น Java จึงไม่รองรับการสืบทอดหลายรายการ! แต่มีช่องโหว่ซึ่งเราจะพูดถึงต่อไป ดังที่ฉันได้กล่าวไว้ก่อนหน้านี้ ด้วยการเปิดตัว Java 8 ความสามารถในการมีวิธีการเริ่มต้นถูกเพิ่มลงใน อิน เทอร์เฟซ หากคลาสที่ใช้อินเทอร์เฟซไม่ได้แทนที่วิธีการนี้ การใช้งานเริ่มต้นนี้จะถูกนำมาใช้ (ไม่จำเป็นต้องแทนที่วิธีการเริ่มต้น เช่น การใช้วิธีนามธรรม) ในกรณีนี้ คุณสามารถปรับใช้อินเทอร์เฟซที่แตกต่างกันในคลาสเดียวและใช้วิธีการเริ่มต้นได้ ลองดูตัวอย่าง เรามีอินเทอร์เฟซของใบปลิว โดยมีเมธอดfly() เริ่มต้น :public interface Flyer {
default void fly() {
System.out.println("Я лечу!!!");
}
}
อินเทอร์เฟซของวอล์คเกอร์ด้วยเมธอดwalk() เริ่มต้น :
public interface Walker {
default void walk() {
System.out.println("Я хожу!!!");
}
}
อินเทอร์เฟซนักว่ายน้ำด้วย เมธอด swim() :
public interface Swimmer {
default void swim() {
System.out.println("Я плыву!!!");
}
}
ตอนนี้เรามาปรับใช้ทั้งหมดนี้ในคลาสเป็ดเดียว:
public class Duck implements Flyer, Swimmer, Walker {
}
และลองใช้วิธีการทั้งหมดของเป็ดของเรา:
Duck donald = new Duck();
donald.walk();
donald.fly();
donald.swim();
ในคอนโซลเราจะได้รับ:

- เปลี่ยนชื่อวิธีการในอินเทอร์เฟซเพื่อให้แตกต่างกัน
- แทนที่วิธีการขัดแย้งดังกล่าวในคลาสการใช้งาน
- สืบทอดจากคลาสที่ใช้วิธีการที่มีการโต้แย้งเหล่านี้ (จากนั้นคลาสของคุณจะใช้การนำไปใช้งานทุกประการ)
8. อะไรคือความแตกต่างระหว่างเมธอด Final, ในที่สุด และ Finalize()?
Finalเป็นคีย์เวิร์ดที่ใช้เพื่อกำหนดข้อจำกัดในคลาส เมธอด หรือตัวแปร ซึ่งหมายถึงข้อจำกัด:- สำหรับตัวแปร - หลังจากการกำหนดค่าเริ่มต้นแล้ว ตัวแปรจะไม่สามารถกำหนดใหม่ได้
- สำหรับวิธีการนั้น ไม่สามารถแทนที่วิธีการในคลาสย่อยได้ (คลาสที่สืบทอด)
- สำหรับคลาส - ไม่สามารถสืบทอดคลาสได้

GO TO FULL VERSION