웹개발/JAVA

내부 클래스(Inner Class, Nested Class)

bergerac 2025. 3. 6. 09:11

내부(중첩) 클래스(Inner Class, Nested Class) 란?

  • 다른 클래스 내부에 선언된 클래스를 의미한다.
  • 코드의 가독성이 향상되고 코드의 구조를 파악하기에 용이하다.
  • 클래스 간의 관계를 명확하게 표현하여 내부 클래스는 외부 클래스의 멤버에 접근 가능하다.

종류

1. (비정적)내부 클래스(Non - Static Inner Class)

  • 반드시 외부 클래스의 인스턴스가 있어야만 생성할 수 있는 클래스이다.
  • 외부 클래스의 인스턴스에 속하기에 외부 클래스의 인스턴스 변수 및 메서드에 직접적인 접근이 가능하다.
  • 외부 클래스와 밀접한 관련이 있는 경우 사용한다.

<비정적 내부 클래스> - 인스턴스 멤버처럼 사용

class InnerClass{
    void display(){
        System.out.println("외부 클래스 필드에 접근 : "+outerField);
    }
}

 

<사용방법>

1) 외부 클래스 인스턴스화

OuterClass outerClass1 = new OuterClass();

2) 외부 클래스 내부 클래스 형식으로 내부 클래스 인스턴스를 생성한다.

외부클래스타입.내부클래스타입 변수명 = 외부 인스턴스.new 내부클래스();

 

2. 정적 내부 클래스(Static Inner Class)

  • 외부 클래스의 정적 멤버에 속한다.
  • 외부 클래스의 인스턴스 변수에 접근하지 못한다
  • 외부 클래스의 정적 멤버에만 접근이 가능하다
  • 외부 클래스의 인스턴스 생성 없이 인스턴스화가 가능하다.
static class StaticClass{
    void display(){
        //System.out.println("외부 클래스 필드에 접근 : "+outerField);-오류발생
        //외부 필드에 접근하지 못한다.
        System.out.println("외부 클래스 정적 필드에 접근"+staticField);
    }
}
외부 클래스타입. 내부 클래스타입 변수명 = new 외부클래스명.내부클래스();
OuterClass.StaticClass staticClass = new OuterClass.StaticClass();
staticClass.display();

 

3. 메서드 내부 클래스(지역 클래스)(Method Inner Class)

  • 메서드 내에서 정의된 내부 클래스이다
  • 해당 메서드 내에서만 사용이 가능하다
  • 메서드의 지역변수에만 접근이 가능하다.
  • 로컬 변수(외부 클래스 멤버 변수)가 final인 경우에만 접근이 가능하다.

>>>> 외부에 있는 로컬 변수 아무렇게나 접근해서 변수값을 바꿔버릴가봐 final 인 경우에만 접근이 가도록 설정할 할 수 있다.

 

 

 

외부에서 인스턴스화가 불가능 하기 때문에 다음과 같이 인스턴스화도 내부에서 해 주어야 한다.

void outerMethod() {
    String localVar = "메서드 로컬 변수";
    // localVar = "메서드 로컬 변수 값 변경"; - 지역 변수는 암묵적으로 final로 간주 (생략 가능)
    final String localFinalVar = "메서드 로컬 변수 (Final)";
    // localFinalVar = "메서드 로컬 변수 값 변경";

    class MethodClass {
        void display() {
            System.out.println("로컬 변수에 접근(Final X): " + localVar);
            System.out.println("로컬 변수에 접근(Final O): " + localFinalVar);
        }
    }

    System.out.println("외부 클래스의 메서드를 호출");

    // 로컬 클래스의 인스턴스화
    // : 메서드 내부에서만 쓰이기 때문에 인스턴스화도 내부에서 일어남
    MethodClass methodClass = new MethodClass();
    methodClass.display();
}






 

System.out.println("=== 메서드 내부 클래스 (지역 클래스) ===");
OuterClass outerClass2 = new OuterClass();
outerClass2.outerMethod();

 

4. 익명(내부)클래스(Anonymous Inner Class)

 

이름이 없는 내부 클래스, 주로 인터페이스나 추상 클래스의 구현에 사용한다.

즉시 객체 생성이 가능하고 주로 클래스를 일회성으로 사용하는 경우에 사용한다.

 

 

예제 1)

abstract class Greeting {
    abstract void sayHello();
}

public class Main {
    public static void main(String[] args) {
        // 첫 번째 익명 내부 클래스 인스턴스
        Greeting greeting1 = new Greeting() {
            private int count = 0; // 익명 내부 클래스의 멤버 변수

            @Override
            void sayHello() {
                count++;
                System.out.println("Hello from greeting1! Count: " + count);
            }
        };

        // 두 번째 익명 내부 클래스 인스턴스 (greeting1과 완전히 별개)
        Greeting greeting2 = new Greeting() {
            private int count = 0; // 새로운 멤버 변수 (greeting1과 공유되지 않음)

            @Override
            void sayHello() {
                count++;
                System.out.println("Hello from greeting2! Count: " + count);
            }
        };

        // 각각 호출해보기
        greeting1.sayHello(); // Hello from greeting1! Count: 1
        greeting1.sayHello(); // Hello from greeting1! Count: 2

        greeting2.sayHello(); // Hello from greeting2! Count: 1
        greeting2.sayHello(); // Hello from greeting2! Count: 2
    }
}

 

예제 2)

// 추상 클래스: 하나 이상의 추상 메서드를 포함
        abstract class AbstractClass {
            // cf) 추상 클래스는 구현 클래스를 가질 수 있음
            //     >> 추상 메서드에 abstract 키워드 생략 X
            abstract void display(); // 추상 메서드: 구현부 {}가 없는 메서드
        }

// 인터페이스
        interface InterfaceClass {
            // cf) 필드는 public static final 생략

            // cf) 인터페이스는 일반 구현 클래스를 가질 수 없음
            //     >> static 메서드, default 메서드 가능 (예외)
            void something(); // public abstract 생략
        }

<Main>

  System.out.println("=== 익명 (내부) 클래스 ===");
    // 클래스타입 변수명 = new 클래스명() { 메서드 구현 - 추상클래스/인터페이스의 추상 메서드 }
    AbstractClass abstractClass1 = new AbstractClass() {
        @Override
        void display() {
            System.out.println("익명 내부 클래스 - 추상 클래스1");
        }
    };

    abstractClass1.display();

    AbstractClass abstractClass2 = new AbstractClass() {
        @Override
        void display() {
            System.out.println("익명 내부 클래스 - 추상 클래스2");
        }
    };

    abstractClass2.display();

    System.out.println(abstractClass1 == abstractClass2); // false

    // >> 재사용될 필요가 없거나, 단 한번의 사용 목적에 유용

    InterfaceClass interfaceClass = new InterfaceClass() {
        @Override
        public void something() {
            System.out.println("안녕하세요! 익명 클래스입니다 :)");
        }
    };

    interfaceClass.something();
}

Java의 내부 클래스(Inner Class)와 익명 클래스(Anonymous Class)는 코드의 가독성과 유지보수성을 높이면서, 외부 클래스와 밀접하게 연결된 기능을 모듈화할 수 있는 강력한 도구입니다. 특히, 익명 클래스는 단 한 번 사용될 간단한 로직을 구현할 때 매우 유용합니다. 추상 클래스나 인터페이스를 손쉽게 구현할 수 있으므로, 필요한 순간에 간단히 사용할 수 있습니다.

 

내부 클래스 비교 정리

 

비정적 내부 클래스 외부 클래스의 인스턴스가 필요 outer.new Inner(); O (가능)
정적 내부 클래스 외부 클래스의 인스턴스 없이 사용 가능 new Outer.StaticInner(); X (불가능)
메서드 내부 클래스 메서드 내부에서만 사용 가능 메서드 내부에서 직접 생성 O (가능, 단 final 지역 변수만 접근 가능)
익명 내부 클래스 일회성 사용, 인터페이스/추상 클래스 구현 클래스 선언 없이 즉시 객체 생성 O (가능)

 

 

내부 클래스를 선택할 때는 각 클래스 유형의 특성과 목적을 잘 파악하여, 비정적/정적/지역/익명 클래스 중 알맞은 방식을 적용하면 됩니다. 이로써 코드 구조를 명확히 하고, 로직을 한눈에 파악할 수 있게 만들 수 있습니다.

 

'웹개발 > JAVA' 카테고리의 다른 글

캡슐화(Encapsulation// getter&setter)  (1) 2025.03.08
람다식(Lambda)– 기본 문법  (1) 2025.03.07
결합도(Coupling)와 응집도(Cohesion)  (0) 2025.03.05
SOLID 원칙  (0) 2025.03.04
API - Java Util Package  (1) 2025.03.03