[김영한의 실전 자바 중급편1] - 중첩, 내부 클래스2

jkky98·2024년 5월 26일
0

Java

목록 보기
20/51

지역 클래스

지역 클래스(Local class)는 내부 클래스의 특별한 종류의 하나이며 지역 클래스도 바깥 클래스의 인스턴스 멤버에 접근이 가능하다.(외부 클래스에 종속적이다.)

지역 클래스는 지역 변수처럼 코드 블록 안에 클래스를 선언한다. 내부 클래스보다 더 안쪽에 위치한다고 볼 수 있다. 하지만 선언 형식은 내부 클래스와 동일하다.

내부 클래스와 지역 클래스의 주요 구분점은 위치에 있다. 내부 클래스는 클래스 내부에 위치하며, 지역 클래스는 지역 변수 부분에 위치한다. 이로 인해 지역 클래스는 해당 코드 블록 내에서만 유효하게 된다.

지역 변수 캡쳐

코드 블록의 실행 생명 주기를 생각해보자. 특정 메서드 안의 지역 변수는 메서드가 끝나면 사라지게 된다(스택 영역). 그렇다면, 지역 클래스로 만든 객체는 어떻게 될까? 객체는 힙 영역에서 생성되므로, 더 오랫동안 살아남으며 GC(가비지 컬렉션)의 대상이 된다.

만약 지역 객체(힙 영역, GC 대상)가 지역 변수(스택 영역)를 활용하고 있다면, 일반적으로는 지역 변수가 스택에서 삭제될 때 지역 클래스 인스턴스에서 에러가 발생해야 할 것 같다. 하지만 사실, 지역 클래스는 생성 시점에 이미 지역 변수를 캡쳐해서 객체 내부로 가져오기 때문에, 지역 변수는 스택에서 사라지지 않고 지역 클래스 인스턴스에 안전하게 저장된다.

따라서, 지역 클래스에 의해 생성된 인스턴스는 접근이 필요한 지역 변수만을 캡쳐하여 저장하고, 이후에도 그 값을 안전하게 사용할 수 있다.

지역 클래스가 접근하는 지역 변수

지역 클래스가 접근하는 지역 변수는 단순히 "변하면 안 된다"고 배울 때가 많다. 하지만, 지역 변수 캡쳐에 대한 내용을 알게 되면, 자연스럽게 지역 변수가 바뀌면 안 된다고 생각하게 된다. 그 이유는, 지역 변수를 바꾸더라도 지역 클래스는 이미 해당 지역 변수를 캡쳐해가므로, 지역 클래스 내에서는 변경된 값을 반영할 수 없다.

이러한 동작을 이해하면, 자동으로 바뀌기를 기대하는 것은 불가능하다는 점을 알게 된다. 지역 클래스와 지역 변수는 각각 스택 영역힙 영역에 존재하며, 이들은 삭제 기간이 다르기 때문이다. 따라서, 지역 변수를 변경하더라도 지역 클래스에는 그 변경을 반영할 수 없으며, 이를 변경하지 않는 방식으로 통일하는 것이 맞다.

그러므로 지역 클래스가 접근하는 지역 변수는 항상 final로 선언해야한다. 이것은 자바 문법이며 규칙이다.

public class LocalClassExample {
    public static void main(String[] args) {
        // 지역 변수를 final로 선언
        final int num = 10;

        // 지역 클래스 정의
        class LocalClass {
            public void printValue() {
                // 지역 변수에 접근
                System.out.println("Captured value: " + num);
            }
        }

        // 지역 클래스 인스턴스 생성 및 메서드 호출
        LocalClass localClass = new LocalClass();
        localClass.printValue();
    }
}

익명 클래스

// 지역 class 외부
public void process(int paramVar) {
	int localVar = 1;
    
    class LocalPrinter implements Printer {
    	int value = 0;
        ...
        }
    }

위의 예시에서 지역클래스인 LocalPrinter는 Printer의 구현체이다.

// 지역 class 외부
public void process(int paramVar) {
	int localVar = 1;
    
    Printer printer = new Printer() {
    	int value = 0;
        ...
        }
    }

이렇게 인터페이스인 printer객체를 생성하면서 밑에 익명으로 오버라이딩된 구현 기능이나 맴버변수를 삽입할 수 있다.

new Interface() {body}

익명 클래스는 클래스의 본문(body)을 정의하면서 동시에 생성하는 방식이다. new 뒤에 바로 상속받을 부모 타입(또는 인터페이스)을 입력하면 된다. 자바에서는 인터페이스를 직접 생성할 수 없기 때문에, 이는 해당 인터페이스를 구현한 익명 클래스를 생성하는 방식이다.

하지만 익명 클래스는 단 한 번의 생성만 허용된다. 객체를 생성하면서 구현체에 대한 정보를 제공하는 것이기 때문에, 특정 상황에 맞는 목적에 맞게 한정적으로 사용해야 한다.

profile
자바집사의 거북이 수련법

0개의 댓글