[JAVA] 내부 클래스

JHJeong·2024년 4월 16일
0

내부 클래스

내부 클래스는 그 이름에서 알 수 있듯이, 하나의 클래스 안에 또 다른 클래스가 정의되어 있는 형태를 말한다. 이 구조는 특정 클래스 내에서만 사용되는 보조 클래스를 그 범위 내에서만 유지하여 외부에는 노출시키지 않는 캡슐화를 강화할 수 있다. 내부 클래스는 주로 외부 클래스와 강하게 연결된 작업을 수행하거나, 외부 클래스의 코드를 간결하게 만들기 위해 사용된다.

이렇게 내부 클래스를 사용함으로써, 개발자는 더욱 체계적이고 구조화된 코드를 작성할 수 있다. 코드의 재사용성과 유지보수성이 향상되며, 복잡한 문제를 좀 더 단순하고 직관적으로 해결할 수 있는 방법을 제공한다. 또한, 이벤트 드리븐 프로그래밍에서는 콜백 함수나 이벤트 핸들러를 내부 클래스를 통해 구현함으로써, 이벤트 처리 로직을 효과적으로 캡슐화할 수 있다.

1. 멤버 내부 클래스(Member Inner Class)

  • 외부 클래스의 인스턴스 멤버로 선언된 클래스
  • 외부 클래스의 인스턴스 변수에 접근할 수 있음
  • 주로 외부 클래스의 기능을 보완하거나 확장하는 데 사용됨
public class OuterClass {
    private int outerField = 10;

    // Member Inner Class
    public class InnerClass {
        public void innerMethod() {
            System.out.println("Inner method with outerField value: " + outerField);
        }
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        OuterClass.InnerClass inner = outer.new InnerClass();
        inner.innerMethod(); // Output: Inner method with outerField value: 10
    }
}

출력 결과
Inner method with outerField value: 10

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

  • 'static'키워드로 선언된 클래스로, 외부 클래스의 인스턴스에 묶이지 않음
  • 외부 클래스의 정적 멤버에만 접근할 수 있음
  • 주로 외부 클래스와 관련된 보조 기능을 제공하는데 사용됨
public class OuterClass {
    private static int outerStaticField = 20;

    // Static Nested Class
    public static class StaticNestedClass {
        public void staticMethod() {
            System.out.println("Static method of StaticNestedClass with outerStaticField value: " + outerStaticField);
        }
    }

    public static void main(String[] args) {
        OuterClass.StaticNestedClass nested = new OuterClass.StaticNestedClass();
        nested.staticMethod(); // Output: Static method of StaticNestedClass with outerStaticField value: 20
    }
}

출력 결과
Static method of StaticNestedClass with outerStaticField value: 20

3. 지역 내부 클래스(Local Inner Class)

  • 메서드 내부에 선언된 클래스로, 해당 메서드 내에서만 유효함
  • 주로 메서드 내부의 특정 로직을 캡슐화하고 재사용을 높이는 데 사용됨
public class OuterClass {
    public void outerMethod() {
        int localVariable = 30;

        // Method with Local Inner Class
        class LocalInnerClass {
            public void localMethod() {
                System.out.println("Local method of LocalInnerClass with localVariable value: " + localVariable);
            }
        }

        LocalInnerClass inner = new LocalInnerClass();
        inner.localMethod(); // Output: Local method of LocalInnerClass with localVariable value: 30
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.outerMethod();
    }
}

출력 결과
Local method of LocalInnerClass with localVariable value: 30

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

  • 클래스 이름 없이 정의된 클래스로, 인터페이스나 추상 클래스의 구현을 인라인으로 제공함
  • 주로 이벤트 핸들러나 콜백함수를 구현하는 데 사용됨
public class OuterClass {
    public void anonymousMethod() {
        Runnable runnable = new Runnable() {
            @Override
            public void run() {
                System.out.println("Anonymous inner class's run method");
            }
        };
        new Thread(runnable).start();
    }

    public static void main(String[] args) {
        OuterClass outer = new OuterClass();
        outer.anonymousMethod(); // Output: Anonymous inner class's run method
    }
}

출력 결과
Anonymous inner class's run method

내부 클래스는 주로 다음과 같은 곳에서 사용됨

  • 캡슐화(Encapsulation) : 외부 클래스의 복잡성을 줄이고 관련 기능을 하나로 그룹화함
  • 코드 구조화(Code Structuring) : 관련 있는 코드를 논리적으로 그룹화하여 가독성을 향상시킴
  • 콜백 및 이벤트 처리(Callback and Event Handling) : 인터페이스를 구현하거나 추상 클래스를 확장하여 이벤트 처리나 콜백함수를 구현함
  • 테스트용 목 객체(Test Stub Objects) : 테스트 중에 모의 객체를 만들어 외부 의존성을 제거하고 테스트 가능한 코드를 작성함.

위 에서 콜백 및 이벤트 처리에서 어떻게 사용되는지 예제 소스를 한번 보자.

// Interface for event listeners
interface OnClickListener {
    void onClick();
}

public class Button {
    private OnClickListener onClickListener;

    // Method to register click event listener
    public void setOnClickListener(OnClickListener onClickListener) {
        this.onClickListener = onClickListener;
    }

    // Inner class representing click event handler
    public class ClickHandler {
        public void handleClick() {
            if (onClickListener != null) {
                onClickListener.onClick();
            }
        }
    }

    public void simulateClick() {
        ClickHandler clickHandler = new ClickHandler();
        clickHandler.handleClick();
    }

    public static void main(String[] args) {
        Button button = new Button();
        button.setOnClickListener(() -> System.out.println("Button clicked"));
        button.simulateClick(); // Output: Button clicked
    }
}

출력 결과
Button clicked

이렇게 내부 클래스를 사용하여 ClickHandler 클래스를 구현하여 setOnClickListener를 구현한다.

내부 클래스는 Java 프로그래밍에서 코드의 구조와 디자인을 개선하는 데 중요한 역할을 한다. 각각의 내부 클래스 유형(멤버 내부 클래스, 정적 내부 클래스, 지역 내부 클래스, 그리고 익명 내부 클래스)은 그 특성에 따라 다양한 상황에서 유용하게 사용된다. 이들은 코드의 캡슐화를 강화하고, 관련 기능을 근접하게 위치시켜 프로젝트의 구조를 더욱 명확하게 만든다. 또한, 테스트 가능성을 향상시키고, 코드의 재사용성을 높이며, 복잡한 이벤트 처리나 콜백 구현을 단순화한다.

내부 클래스를 사용할 때는 각 클래스의 범위와 연관성을 명확히 정의하는 것이 중요하다. 외부 클래스의 데이터에 강하게 의존하는 기능이나, 특정 메서드 내에서만 사용되는 클래스는 내부 클래스로 구현하여 외부에서의 불필요한 접근을 제한함으로써 보안성을 높이고, 코드를 깔끔하게 유지할 수 있다. 또한, 익명 내부 클래스를 활용하여 간단한 인터페이스나 추상 클래스의 구현을 인라인으로 제공함으로써 코드의 직관성을 개선할 수 있다.

결국, 내부 클래스는 Java 개발자의 도구 상자에서 매우 강력한 도구라고 할 수 있다. 적절히 활용한다면, 소프트웨어의 설계를 더욱 견고하고 유지보수하기 쉽게 만들어 줄 것 이다. 따라서, 각 프로젝트의 요구 사항과 문제에 맞게 내부 클래스를 전략적으로 사용하여, 보다 효율적인 프로그래밍을 해야한다.

profile
이것저것하고 싶은 개발자

0개의 댓글