안녕! 오늘 수업에서는 중첩 클래스에 대한 주제를 계속 살펴보겠습니다. 이제 마지막 그룹인 익명의 내부 클래스를 위한 시간입니다. 다이어그램으로 돌아가 보겠습니다.
지난 수업에서 이야기한 로컬 클래스와 마찬가지로 익명 클래스도 일종의 내부 클래스입니다... 또한 몇 가지 유사점과 차이점이 있습니다. 그러나 먼저, 자세히 살펴보겠습니다. 왜 정확히 "익명"이라고 불립니까? 이에 답하기 위해 간단한 예를 살펴보겠습니다. 지속적으로 실행되고 무언가를 수행하는 기본 프로그램이 있다고 상상해 보십시오. 여러 모듈로 구성된 이 프로그램에 대한 모니터링 시스템을 만들고자 합니다. 하나의 모듈은 성능의 일반적인 지표를 추적하고 로그를 유지합니다. 두 번째는 오류 로그에 오류를 등록하고 기록합니다. 세 번째는 무단 액세스 시도 및 기타 보안 관련 사항과 같은 의심스러운 활동을 추적합니다. 본질적으로 세 모듈 모두 프로그램 시작 부분에서 시작하고 백그라운드에서 실행되어야 하므로,
를 생성 하고 각각에 대한 메서드를 호출하기 만 하면 됩니다. 즉, 우리가 해야 할 일은 3개의 객체를 생성하고 그들에 대해 1개의 메서드를 호출하는 것입니다.

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개의 객체( , , ) 
GeneralIndicatorMonitoringModule
ErrorMonitoringModule
SecurityModule
startMonitoring()
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