본문 바로가기
Java/객체지향 프로그래밍 기초

6. 내부 클래스(Inner Class)

by mozzi329 2022. 7. 8.
728x90
 

 

     

    마트료시카

    📌 Goal

    • 내부 클래스의 기본 개념과 장점에 대해 이해할 수 있다.
    • 선언 위치에 따른 내부 클래스의 종류와 특징에 대해 이해하고 설명할 수 있다.
    • 내부 클래스의 종류에 따른 유효 범위와 접근성을 이해할 수 있다.

     

    📌 내부 클래스(Inner Class)

    외부 클래스와 내부 클래스가 서로 연관되어 있을 때 사용하는 클래스로 클래스 내부에 선언하는 클래스

    내부 클래스를 사용하면 외부 클래스의 멤버들에 쉽게 접근 할 수 있고, 코드의 복잡성을 줄일 수 있다. 또한 외부적으로 불필요한 데이터를 감출 수 있어 객체지향의 중요한 핵심 원칙인 캡슐화(encapsulation)를 달성하는 데 유용하다. 아래의 예제 코드는 외부 클래스와 그 안에 포함될 수 있는 세가지의 내부 클래스 종류를 나타낸다. 이 외에도 클래스의 선언과 객체의 생성을 동시에 수행하는 일회용 내부 클래스인 익명 내부 클래스가 있다.

    class Outer { // 외부 클래스
    
    	// 익명 내부 클래스
    
    	class Inner {
    		// 인스턴스 내부 클래스
    	}
    
    	static class StaticInner {
    		// 정적 내부 클래스
    	}
    
    	void run() {
    		class LocalInner {
    		// 지역 내부 클래스
    		}
    	}
    }
    

     

    세 가지 내부 클래스의 종류는 각각 인스턴스 내부 클래스, 정적 내부 클래스, 그리고 지역 내부 클래스로 구분할 수 있다. 기본적으로 내부 클래스는 외부 클래스 내에 선언된다는 점을 제외하면 일반 클래스와 차이점이 없다. 단지 외부 클래스와 내부 클래스가 서로 연관되어 있을 때 사용의 편의성을 고려하여 만들어진 문법 요소라고 할 수 있다. 또한 이 세 가지 내부 클래스는 변수가 선언 위치에 따라 인스턴스 변수, 클래스 변수, 그리고 지역 변수로 구분되는 것과 유사하게 위치를 중심으로 구분될 수 있고, 그 유효범위(scope)와 특성이 변수의 특성과 유사하다고 볼 수 있다.

     

    ✔️ 내부 클래스(Inner Class) 종류

    종 류 선언 위치 사용가능한 변수
    인스턴스 내부 클래스(instance inner class) 외부 클래스의 멤버변수 선언위치에 선언(멤버 내부 클래스) 외부 인스턴스 변수, 외부 전역 변수
    정적 내부 클래스(static inner class) 외부 클래스의 멤버변수 선언위치에 선언(멤버 내부 클래스) 외부 전역 변수
    지역 내부 클래스(local inner class) 외부 클래스의 메서드나 초기화블럭 안에 선언 외부 인스턴스 변수, 외부 전역 변수
    익명 내부 클래스(anonymous inner class) 클래스의 선언과 객체의 생성을 동시에 하는 일회용 익명 클래스 외부 인스턴스 변수, 외부 전역 변수

     

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

    인스턴스 내부 클래스와 정적 내부클래스를 하나로 묶어 멤버 내부 클래스라고 통칭

    ✔️ 인스턴스 내부 클래스(Instance Inner Class)

    인스턴스 내부 클래스(Instance Inner Class)는 객체 내부에 멤버의 형태로 존재하며, 외부 클래스의 모든 접근 지정자의 멤버에 접근이 가능하다.

    아래의 예제 코드를 보면 인스턴스 내부 클래스는 외부 클래스의 내부에 위치해 있으며 private접근 제어자를 사용하고 있음에도 내부에서 외부 클래스의 인스턴스 변수와 정적 변수에 각각 접근하여 해당 값을 사용하고 있다.

     

    ※ private 접근 제어자란?

    private 접근 제어자를 사용하여 선언된 클래스 멤버는 외부에 공개되지 않으며, 외부에서는 직접 접근할 수 없다. 즉, 자바 프로그램은 private 멤버에 직접 접근할 수 없으며, 해당 객체의 public 메소드를 통해서만 접근할 수 있다.

     

    class Outer { //외부 클래스
        private int num = 1; //외부 클래스 인스턴스 변수
        private static int sNum = 2; // 외부 클래스 정적 변수
    
        private InClass inClass; // 내부 클래스 자료형 변수 선언
    
        public Outer() {
            inClass = new InClass(); //외부 클래스 생성자
        }
    
        class InClass { //인스턴스 내부 클래스
            int inNum = 10; //내부 클래스의 인스턴스 변수
    
            void Test() {
                System.out.println("Outer num = " + num + "(외부 클래스의 인스턴스 변수)");
                System.out.println("Outer sNum = " + sNum + "(외부 클래스의 정적 변수)");
            }
        }
    
        public void testClass() {
            inClass.Test();
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Outer outer = new Outer();
            System.out.println("외부 클래스 사용하여 내부 클래스 기능 호출");
            outer.testClass(); // 내부 클래스 기능 호출
        }
    }
    
    // 출력값
    
    외부 클래스 사용하여 내부 클래스 기능 호출
    Outer num = 1(외부 클래스의 인스턴스 변수)
    Outer sNum = 2(외부 클래스의 정적 변수)
    

    ❗️주의해야할 점

    인스턴스 내부 클래스는 반드시 외부 클래스를 생성한 이후에 사용해야 한다.

    그러므로 클래스의 생성과 상관없이 사용할 수 있는 정적 변수와 정적 메서드는 인스턴스 내부 클래스에서 선언할 수 없다.

     

    ✔️ 정적 내부 클래스(Static Inner Class)

    정적 내부 클래스(Static Inner Class)를 사용하면 내부 클래스가 외부 클래스의 존재와 무관하게 정적 변수를 사용할 수 있다.

    앞서 내부 클래스가 기본적으로 외부 클래스의 존재에 의존하는 인스턴스 내부 클래스(Instance Inner Class)와 달리 static 키워드를 통해 외부 클래스와의 의존 관계 없이 정적 변수를 사용할 수 있다.

     

    class Outer { //외부 클래스
        private int num = 3; //내부 클래스의 인스턴스 변수
        private static int sNum = 4;
    
        void getPrint() {
            System.out.println("인스턴스 메서드");
        }
    
        static void getPrintStatic() {
            System.out.println("스태틱 메서드");
        }
    
        static class StaticInClass { // 정적 내부 클래스
            void test() {
                System.out.println("Outer num = " +sNum + "(외부 클래스의 정적 변수)");
                getPrintStatic();
                // num 과 getPrint() 는 정적 멤버가 아니라 사용 불가.
            }
        }
    }
    
    public class Main {
        public static void main(String[] args) {
            Outer.StaticInClass a = new Outer.StaticInClass(); //정적 이너 클래스의 객체 생성
            a.test();
        }
    }
    
    //출력값
    Outer num = 4(외부 클래스의 정적 변수)
    스태틱 메서드
    

     

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

    클래스의 멤버가 아닌 메서드 내에서 정의되는 클래스

    지역 내부 클래스도 지역 변수와 유사하게 메서드 내부에서만 사용가능하기 때문에 일반적으로 메서드 안에서 선언 후에 바로 객체를 생성해서 사용한다. 아래 코드 예제를 보면 지역 내부 클래스 LocalInClass가 메서드 안에서 선언되고 생성된 후에 정의된 메서드를 호출하여 외부 클래스의 변수들을 출력하고 있는 것을 확인할 수 있다.

    class Outer { //외부 클래스
        int num = 5;
        void test() {
            int num2 = 6;
            class LocalInClass { //지역 내부 클래스
                void getPrint() {
                    System.out.println(num);
                    System.out.println(num2);
                }
            }
            LocalInClass localInClass = new LocalInClass();
            localInClass.getPrint();
        }
    }
    public class Main {
        public static void main(String[] args) {
            Outer outer = new Outer();
            outer.test();
        }
    }
    
    //출력값
    5
    

    댓글