สวัสดี! ในบทเรียนวันนี้ เราจะตรวจสอบหัวข้อของชั้นเรียนที่ซ้อนกันต่อไป ถึงเวลาสำหรับกลุ่มสุดท้าย: คลาสภายในที่ไม่ระบุชื่อ กลับไปที่ไดอะแกรมของเรา:
เช่นเดียวกับคลาสท้องถิ่นที่เราพูดถึงในบทเรียนที่แล้ว คลาสนิรนามเป็นคลาสภายในประเภทหนึ่ง... พวกเขายังมีความเหมือนและความแตกต่างหลายประการ แต่ก่อนอื่น มาเริ่มกันเลย: ทำไมพวกเขาถึงเรียกว่า "ไม่ระบุชื่อ" เพื่อตอบคำถามนี้ ลองพิจารณาตัวอย่างง่ายๆ ลองนึกภาพว่าเรามีโปรแกรมพื้นฐานที่ทำงานและทำอะไรบางอย่างอยู่ตลอดเวลา เราต้องการสร้างระบบตรวจสอบสำหรับโปรแกรมนี้ ซึ่งประกอบด้วยหลายโมดูล โมดูลหนึ่งจะติดตามตัวบ่งชี้ทั่วไปของประสิทธิภาพและเก็บรักษาบันทึก ที่สองจะลงทะเบียนและบันทึกข้อผิดพลาดในบันทึกข้อผิดพลาด ส่วนที่สามจะติดตามกิจกรรมที่น่าสงสัย ตัวอย่างเช่น ความพยายามในการเข้าถึงโดยไม่ได้รับอนุญาต และสิ่งที่เกี่ยวข้องกับความปลอดภัยอื่นๆ เนื่องจากโดยพื้นฐานแล้วทั้งสามโมดูลควรเริ่มต้นที่จุดเริ่มต้นของโปรแกรมและทำงานในพื้นหลัง
โดยพื้นฐานแล้ว เราเพียงแค่ต้องสร้างวัตถุ 3 ชิ้น —

public interface MonitoringSystem {
public void startMonitoring();
}
3 คลาสที่เป็นรูปธรรมจะดำเนินการ:
public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
}
public class ErrorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
}
public class SecurityModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor security!");
}
}
ดูเหมือนว่าทุกอย่างจะเรียบร้อย เรามีระบบที่ค่อนข้างเชื่อมโยงกันซึ่งประกอบด้วยหลายโมดูล แต่ละคนมีพฤติกรรมของตัวเอง หากเราต้องการโมดูลใหม่ เราสามารถเพิ่มได้ เนื่องจากเรามีอินเทอร์เฟซที่ใช้งานได้ง่าย แต่ลองคิดดูว่าระบบตรวจสอบของเราจะทำงานอย่างไร 
GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
, SecurityModule
— และเรียกใช้startMonitoring()
เมธอดสำหรับแต่ละวัตถุ นั่นคือทั้งหมดที่เราต้องทำคือสร้างวัตถุ 3 ชิ้นและเรียกใช้ 1 วิธีการ
public class Main {
public static void main(String[] args) {
GeneralIndicatorMonitoringModule generalModule = new GeneralIndicatorMonitoringModule();
ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
SecurityModule securityModule = new SecurityModule();
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
เอาต์พุตคอนโซล:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
และด้วยการทำงานเพียงเล็กน้อย เราได้เขียนระบบทั้งหมด: 3 คลาสและอินเทอร์เฟซเดียว! และทั้งหมดนี้เพื่อให้ได้รหัส 6 บรรทัด ในทางกลับกัน ทางเลือกของเราคืออะไร? มันไม่เจ๋งเลยที่เราเขียนคลาส "ครั้งเดียว" เหล่านี้ แต่เราจะแก้ไขได้อย่างไร คลาสภายในนิรนามมาช่วยเราแล้ว! นี่คือลักษณะที่ปรากฏในกรณีของเรา:
public class Main {
public static void main(String[] args) {
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
};
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
};
MonitoringSystem securityModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor security!");
}
};
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
มาดูกันว่าเกิดอะไรขึ้น! ดูเหมือนว่าเรากำลังสร้างวัตถุอินเทอร์เฟซ:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
};
แต่เรารู้มานานแล้วว่าเราไม่สามารถสร้างวัตถุอินเทอร์เฟซได้! และเป็นเช่นนั้น - มันเป็นไปไม่ได้ อันที่จริง นั่นไม่ใช่สิ่งที่เรากำลังทำอยู่ เมื่อเราเขียน:
MonitoringSystem generalModule = new MonitoringSystem() {
};
สิ่งต่อไปนี้เกิดขึ้นภายในเครื่อง Java:
- สร้างคลาส Java ที่ไม่มีชื่อซึ่งใช้
MonitoringSystem
อินเทอร์เฟซ - เมื่อคอมไพลเลอร์เห็นคลาสดังกล่าว คุณต้องใช้เมธอดทั้งหมดของ
MonitoringSystem
อินเทอร์เฟซ (เราทำ 3 ครั้ง) - วัตถุหนึ่งของคลาสนี้ถูกสร้างขึ้น ให้ความสนใจกับรหัส:
MonitoringSystem generalModule = new MonitoringSystem() {
};
มีเครื่องหมายอัฒภาคในตอนท้าย! มันมีเหตุผล เราประกาศคลาสพร้อมกัน (โดยใช้วงเล็บปีกกา) และสร้างอินสแตนซ์ของมัน (โดยใช้();
) อ็อบเจ็กต์ทั้งสามของเราจะแทนที่เมธอดstartMonitoring()
ด้วยวิธีของมันเอง ในที่สุดเราก็เรียกวิธีนี้กับแต่ละวิธี:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
เอาต์พุตคอนโซล:
Starting to monitor general indicators!
Starting to monitor errors!
Starting to monitor security!
แค่นั้นแหละ! เราบรรลุวัตถุประสงค์: เราสร้างMonitoringSystem
วัตถุสามชิ้น ลบล้างวิธีการในสามวิธีที่แตกต่างกัน และเรียกมันสามครั้ง โมดูลทั้งสามได้รับการเรียกสำเร็จและกำลังทำงานอยู่ ในขณะเดียวกันโครงสร้างของโปรแกรมของเราก็ง่ายขึ้นมาก! เพราะตอนนี้ , GeneralIndicatorMonitoringModule
, ErrorMonitoringModule
และSecurityModule
คลาสสามารถลบออกจากโปรแกรมได้ทั้งหมดแล้ว! เราไม่ต้องการพวกเขา - เราทำได้ดีมากหากไม่มีพวกเขา หากคลาสนิรนามของเราแต่ละคลาสต้องการลักษณะการทำงานที่แตกต่างกัน เช่น เมธอดเฉพาะของตัวเองที่คลาสอื่นๆ ไม่มี เราสามารถเพิ่มได้อย่างง่ายดาย:
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor general indicators!");
}
public void someSpecificMethod() {
System.out.println("Specific method only for the first module");
}
};
เอกสาร Oracle ให้คำแนะนำ ที่ดี : "ใช้ [คลาสที่ไม่ระบุตัวตน] ถ้าคุณต้องการใช้คลาสโลคัลเพียงครั้งเดียว" คลาสนิรนามคือคลาสภายในที่เต็มเปี่ยม ดังนั้นจึงสามารถเข้าถึงตัวแปรของคลาสภายนอก รวมถึงตัวแปรสแตติกและไพรเวต:
public class Main {
private static int currentErrorCount = 23;
public static void main(String[] args) {
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
public int getCurrentErrorCount() {
return currentErrorCount;
}
};
}
}
มีบางอย่างที่เหมือนกันกับคลาสโลคัล: มองเห็นได้เฉพาะในเมธอดที่ประกาศเท่านั้น ในตัวอย่างข้างต้น ความพยายามใดๆ ในการเข้าถึงวัตถุerrorModule
นอกmain()
เมธอดจะล้มเหลว และมีข้อจำกัดที่สำคัญอีกข้อหนึ่งที่คลาสนิรนามสืบทอดมาจาก "บรรพบุรุษ" (คลาสภายใน): คลาสนิรนามไม่สามารถมีตัวแปรและเมธอดแบบสแตติกได้ ในตัวอย่างข้างต้น หากเราพยายามทำให้getCurrentErrorCount()
เมธอดคงที่ คอมไพเลอร์จะสร้างข้อผิดพลาด:
// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {
return currentErrorCount;
}
เราจะได้ผลลัพธ์เดียวกันหากเราพยายามประกาศตัวแปรคงที่:
MonitoringSystem errorModule = new MonitoringSystem() {
// Error! Inner classes cannot have static declarations!
static int staticInt = 10;
@Override
public void startMonitoring() {
System.out.println("Starting to monitor errors!");
}
};
และบทเรียนของเราในวันนี้ก็จบลงแล้ว! แม้ว่าเราได้ตรวจสอบกลุ่มสุดท้ายของคลาสที่ซ้อนกัน แต่เรายังไม่จบหัวข้อนี้ เราจะเรียนรู้อะไรเพิ่มเติมเกี่ยวกับคลาสที่ซ้อนกัน แน่นอนคุณจะพบเร็ว ๆ นี้! :)
GO TO FULL VERSION