
중첩 클래스(Nested Class)는 클래스 내부에 정의된 클래스를 의미합니다.
중첩 클래스는 크게 네 가지로 나눌 수 있습니다
static 키워드를 사용하여 선언된 클래스입니다.static 멤버들만 접근할 수 있습니다.중첩 클래스는 이러한 다양한 형태로 자바 프로그램의 구조를 더욱 효율적으로 만들 수 있으며, 특히 코드의 응집도를 높이고 외부 클래스와 관련된 작업을 모듈화할 수 있습니다.
하지만 그만큼 사용 시 주의할 점도 존재하므로 적절한 용도에 맞게 활용하는 것이 중요합니다.
static 키워드를 사용하여 선언된 중첩 클래스입니다. static 멤버들만 접근할 수 있습니다. public class OuterClass {
private int outerInstanceVar = 10;
private static int outerStaticVar = 20;
// 정적 중첩 클래스
public static class StaticNestedClass {
public void display() {
// 외부 클래스의 비정적 멤버에는 접근할 수 없음
// System.out.println("outerInstanceVar: " + outerInstanceVar); // 오류 발생
// 외부 클래스의 정적 멤버에만 접근 가능
System.out.println("outerStaticVar: " + outerStaticVar);
}
}
public static void main(String[] args) {
// 정적 중첩 클래스의 인스턴스 생성
OuterClass.StaticNestedClass nestedObject = new OuterClass.StaticNestedClass();
nestedObject.display();
}
}
outerStaticVar: 20
OuterClass라는 외부 클래스가 있으며, 그 안에 StaticNestedClass라는 정적 중첩 클래스가 정의되어 있습니다. StaticNestedClass는 static으로 선언되었기 때문에 외부 클래스의 인스턴스 없이도 객체를 생성할 수 있습니다.StaticNestedClass 내부에서는 외부 클래스의 정적 멤버인 outerStaticVar에 접근할 수 있습니다. (접근제어자 상관없이 접근 가능합니다.)outerInstanceVar)에는 직접 접근할 수 없습니다.public class OuterClass {
private int outerInstanceVar = 10;
private static int outerStaticVar = 20;
// 내부 클래스
public class InnerClass {
public void display() {
// 외부 클래스의 모든 멤버에 접근 가능
System.out.println("outerInstanceVar: " + outerInstanceVar);
System.out.println("outerStaticVar: " + outerStaticVar);
}
}
public static void main(String[] args) {
// 외부 클래스의 인스턴스 생성
OuterClass outerObject = new OuterClass();
// 내부 클래스의 인스턴스 생성
OuterClass.InnerClass innerObject = outerObject.new InnerClass();
innerObject.display();
}
}
outerInstanceVar: 10
outerStaticVar: 20
OuterClass라는 외부 클래스 내부에 InnerClass라는 내부 클래스가 정의되어 있습니다. InnerClass는 외부 클래스의 인스턴스 변수 outerInstanceVar와 정적 변수 outerStaticVar에 접근하여 값을 출력합니다.final (또는 Java 8 이후로는 사실상 final(Effectively final))이어야 합니다.final을 명시하지 않아도 final로 선언 된다는 의미입니다.public class OuterClass {
private int outerInstanceVar = 10;
public void outerMethod() {
int localVar = 20; // 사실상 final 변수
// 지역 클래스
class LocalClass {
public void display() {
// 외부 클래스의 인스턴스 변수에 접근 가능
System.out.println("outerInstanceVar: " + outerInstanceVar);
// 사실상 final인 메서드의 지역 변수에 접근 가능
System.out.println("localVar: " + localVar);
}
}
// 지역 클래스의 인스턴스 생성 및 메서드 호출
LocalClass localObject = new LocalClass();
localObject.display();
}
public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
outerObject.outerMethod();
}
}
outerInstanceVar: 10
localVar: 20
outerMethod()라는 메서드 내에 LocalClass라는 지역 클래스가 정의되어 있습니다. outerInstanceVar뿐만 아니라, 메서드 내의 지역 변수 localVar에도 접근할 수 있습니다.localVar는 Java 8 이후 사실상 final(Effectively final)로 간주되며, 지역 클래스 내부에서 사용할 수 있습니다. final로 선언되거나 사실상 final이어야 합니다. final 또는 사실상 final로 제한됩니다.public class OuterClass {
public void outerMethod() {
// 익명 클래스 - Runnable 인터페이스 구현
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println("Anonymous class implementation of Runnable");
}
};
// 스레드에서 익명 클래스 실행
new Thread(runnable).start();
}
public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
outerObject.outerMethod();
}
}
Anonymous class implementation of Runnable
Runnable 인터페이스를 구현하는 익명 클래스가 정의되어 있습니다. new Runnable() 구문에서 직접 구현되었으며, 해당 클래스는 run() 메서드를 재정의(오버라이딩)하여 특정 작업을 수행합니다.Runnable 인터페이스를 구현한 다른 클래스 없이도 일회성으로 인터페이스를 구현하여 사용할 수 있습니다.(인수 목록) -> { 실행 코드 } Runnable 예제를 람다 표현식으로 변환하면 다음과 같습니다.public class OuterClass {
public void outerMethod() {
// 람다 표현식 - Runnable 인터페이스 구현
Runnable runnable = () -> System.out.println("Lambda implementation of Runnable");
// 스레드에서 람다 표현식 실행
new Thread(runnable).start();
}
public static void main(String[] args) {
OuterClass outerObject = new OuterClass();
outerObject.outerMethod();
}
}
Runnable 인터페이스는 메서드가 하나만 있는 함수형 인터페이스이므로, 람다 표현식을 사용할 수 있습니다.1. 정적 중첩 클래스 (Static Nested Class)
Map.Entry 인터페이스의 구현체들처럼, 외부 클래스의 특정 자료구조의 노드 역할을 하는 경우.2. 내부 클래스 (Inner Class)
3. 지역 클래스 (Local Class)
4. 익명 클래스 (Anonymous Class)
Runnable 인터페이스를 구현하여 스레드를 생성하거나, 이벤트 리스너를 정의할 때.