CodeGym /จาวาบล็อก /สุ่ม /คลาสที่ไม่ระบุชื่อ
John Squirrels
ระดับ
San Francisco

คลาสที่ไม่ระบุชื่อ

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

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!");
   }
}
ดูเหมือนว่าทุกอย่างจะเรียบร้อย เรามีระบบที่ค่อนข้างเชื่อมโยงกันซึ่งประกอบด้วยหลายโมดูล แต่ละคนมีพฤติกรรมของตัวเอง หากเราต้องการโมดูลใหม่ เราสามารถเพิ่มได้ เนื่องจากเรามีอินเทอร์เฟซที่ใช้งานได้ง่าย แต่ลองคิดดูว่าระบบตรวจสอบของเราจะทำงานอย่างไร คลาสนิรนาม - 3โดยพื้นฐานแล้ว เราเพียงแค่ต้องสร้างวัตถุ 3 ชิ้น — 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:
  1. สร้างคลาส Java ที่ไม่มีชื่อซึ่งใช้MonitoringSystemอินเทอร์เฟซ
  2. เมื่อคอมไพลเลอร์เห็นคลาสดังกล่าว คุณต้องใช้เมธอดทั้งหมดของMonitoringSystemอินเทอร์เฟซ (เราทำ 3 ครั้ง)
  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!");
   }

};
และบทเรียนของเราในวันนี้ก็จบลงแล้ว! แม้ว่าเราได้ตรวจสอบกลุ่มสุดท้ายของคลาสที่ซ้อนกัน แต่เรายังไม่จบหัวข้อนี้ เราจะเรียนรู้อะไรเพิ่มเติมเกี่ยวกับคลาสที่ซ้อนกัน แน่นอนคุณจะพบเร็ว ๆ นี้! :)
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION