안녕하세요! 오늘 수업에서는 중첩 클래스에 대한 주제를 계속해서 살펴보겠습니다. 마지막 그룹인 Java의 익명 내부 클래스 차례입니다. 다이어그램으로 돌아가 보겠습니다. 지난 강의에서 이야기한 로컬 클래스와 마찬가지로 익명 클래스는 내부 클래스의 하위 집합입니다. 그들은 또한 그들 사이에 몇 가지 유사점과 차이점을 가지고 있습니다. 하지만 먼저 알아봅시다. 왜 실제로 "익명"이라고 불리는 걸까요? 이를 위해 간단한 예를 살펴보겠습니다. 끊임없이 실행되고 무언가를 수행하는 메인 프로그램이 있다고 상상해 보세요. 우리는 여러 모듈로 구성된 이 프로그램에 대한 모니터링 시스템을 만들고 싶습니다. 한 모듈은 일반 성능 지표를 모니터링하고 로그를 유지하며, 두 번째 모듈은 오류 로그에 오류를 기록 및 기록하고, 세 번째 모듈은 의심스러운 활동(예: 무단 액세스 시도 및 기타 보안 관련 사항)을 모니터링합니다. 세 가지 모듈 모두 기본적으로 프로그램 시작 부분에서 시작하여 백그라운드에서 실행되어야 하므로 공통 인터페이스를 만드는 것이 좋습니다.
그리고 오늘 우리 수업은 끝났습니다! 중첩 클래스의 마지막 그룹을 다루었지만 아직 이 주제가 끝나지 않았습니다. 중첩 클래스에 관해 다음에는 무엇을 공부할까요? 당신은 곧 알게 될 것입니다! :)
public interface MonitoringSystem {
public void startMonitoring();
}
이는 3개의 특정 클래스로 구현됩니다.
public class GeneralIndicatorsMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
}
public class ErrorMonitoringModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
}
public class SecurityModule implements MonitoringSystem {
@Override
public void startMonitoring() {
System.out.println("Security monitoring started!");
}
}
모든 것이 정상인 것 같습니다. 우리는 여러 모듈로 구성된 상당히 명확한 시스템을 보유하고 있습니다. 그들 각각은 고유한 행동을 가지고 있습니다. 새 모듈이 필요하면 추가할 수 있습니다. 구현하기 매우 쉬운 인터페이스가 있기 때문입니다. 하지만 우리의 모니터링 시스템이 어떻게 작동할지 생각해 봅시다. 기본적으로 , , - 3개의 개체를 만들고 각 개체에 대해 메서드 를 호출하면 됩니다. 즉, 3개의 개체를 만들고 해당 개체에 대해 1개의 메서드를 호출하기만 하면 됩니다. GeneralIndicatorsMonitoringModule
ErrorMonitoringModule
SecurityModule
startMonitoring()
public class Main {
public static void main(String[] args) {
GeneralIndicatorsMonitoringModule generalModule = new GeneralIndicatorsMonitoringModule();
ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
SecurityModule securityModule = new SecurityModule();
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
콘솔 출력:
Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
그리고 이렇게 작은 작업을 위해 우리는 3개의 클래스와 1개의 인터페이스로 전체 시스템을 작성했습니다! 그리고 이 모든 것은 6줄의 코드를 위한 것입니다. 반면에 우리의 선택은 무엇입니까? 예, 우리가 그런 "일회용" 클래스를 작성했다는 것은 별로 멋지지 않습니다. 하지만 어떻게 이 문제를 해결할 수 있을까요? 익명의 내부 클래스가 우리를 도와주는 곳입니다 ! 우리의 경우에는 다음과 같습니다.
public class Main {
public static void main(String[] args) {
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
};
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
};
MonitoringSystem securityModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Security monitoring started!");
}
};
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
}
}
여기서 무슨 일이 일어나고 있는지 알아봅시다! 인터페이스 객체를 생성하는 것처럼 보입니다.
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
};
그러나 우리는 인터페이스 객체를 생성하는 것이 불가능하다는 것을 오랫동안 알고 있었습니다! 그렇죠, 불가능해요. 사실 우리는 그렇게 하지 않습니다. 우리가 쓰는 순간:
MonitoringSystem generalModule = new MonitoringSystem() {
};
Java 시스템 내부에서는 다음이 발생합니다.
- 을 구현하는 이름 없는 Java 클래스가 생성됩니다
MonitoringSystem
. - 이러한 클래스를 보는 컴파일러는 모든 인터페이스 메서드를 구현하도록 요구합니다
MonitoringSystem
(우리는 이 작업을 3번 수행했습니다). - 이 클래스의 객체 하나가 생성됩니다. 코드에 주의하세요:
MonitoringSystem generalModule = new MonitoringSystem() {
};
마지막에 세미콜론이 있어요! 그녀가 거기 서 있는 데에는 이유가 있습니다. 동시에 클래스를 선언하고(중괄호를 통해) 해당 객체를 생성합니다. ();
세 객체 각각은 startMonitoring()
고유한 방식으로 메서드를 재정의했습니다. 결국 우리는 각각에 대해 이 메서드를 간단히 호출합니다.
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
콘솔 출력:
Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
그게 다야! 우리는 작업을 완료했습니다. 세 개의 객체를 생성하고 MonitoringSystem
이를 세 가지 다른 방식으로 재정의하고 세 번 호출했습니다. 세 가지 모듈이 모두 성공적으로 시작되어 작동합니다. 동시에, 우리 프로그램의 구조는 훨씬 더 단순해졌습니다! GeneralIndicatorsMonitoringModule
결국 , ErrorMonitoringModule
이제 수업을 SecurityModule
프로그램에서 완전히 제거할 수 있습니다! 우리는 그것들이 필요하지 않습니다. 그것들 없이도 우리는 잘 관리했습니다. 각 익명 모듈 클래스에 다른 동작, 다른 클래스에는 없는 고유한 특정 메서드가 필요한 경우 쉽게 추가할 수 있습니다.
MonitoringSystem generalModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Monitoring of general indicators has started!");
}
public void someSpecificMethod() {
System.out.println("Specific method for first module only");
}
};
Oracle 문서에는 "일회용 로컬 클래스가 필요한 경우 익명 클래스를 사용하십시오."라는 좋은 권장 사항이 있습니다. 익명 클래스는 본격적인 내부 클래스입니다. 따라서 정적 및 비공개 변수를 포함한 외부 클래스 변수에 액세스할 수 있습니다.
public class Main {
private static int currentErrorsCount = 23;
public static void main(String[] args) {
MonitoringSystem errorModule = new MonitoringSystem() {
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
public int getCurrentErrorsCount() {
return currentErrorsCount;
}
};
}
}
로컬 클래스와 공통점이 있습니다. 즉, 정의된 메서드 내에서만 표시됩니다. 위의 예에서는 errorModule
메서드 외부에서 개체에 액세스하려는 모든 시도가 main()
실패합니다. 그리고 익명 클래스가 "조상"으로부터 상속받은 또 하나의 중요한 제한 사항은 내부 클래스입니다. 익명 클래스는 정적 변수와 메서드를 포함할 수 없습니다 . 위 예제의 메서드를 정적으로 만들려고 하면 getCurrentErrorsCount()
컴파일러에서 오류가 발생합니다.
//error! Inner classes cannot have static declarations
public static int getCurrentErrorsCount() {
return currentErrorsCount;
}
정적 변수를 선언하려고 하면 동일한 결과를 얻습니다.
MonitoringSystem errorModule = new MonitoringSystem() {
//error! Inner classes cannot have static declarations!
static int staticInt = 10;
@Override
public void startMonitoring() {
System.out.println("Bug Tracking Monitoring Started!");
}
};
마지막으로, 이 주제가 최대한 간단하고 명확하게 설명되어 있는 익명 수업 주제에 관한 훌륭한 동영상을 추천해 드릴 수 있습니다. :)
GO TO FULL VERSION