네, 메소드 로컬 내부 클래스(method local inner class)는 지역 final 변수에 접근할 수 있습니다. 그 이유는 final 변수가 힙(heap) 영역에 저장되기 때문에, 해당 변수를 참조하는 내부 클래스 객체가 살아 있는 동안 변수의 값도 함께 유지되기 때문입니다.
메소드 로컬 내부 클래스란?
- 로컬 내부 클래스의 인스턴스는 메소드의 인수로 전달하거나 반환값으로 사용할 수 있으며, 유효한 스코프(범위) 안에서만 사용할 수 있습니다.
- 메소드 로컬 내부 클래스의 가장 큰 제약은, 내부 클래스에서 참조하는 지역 변수나 매개변수는 반드시 final로 선언되어야 한다는 점입니다.
- 메소드의 실행이 끝난 후에도 내부 클래스 객체는 계속 존재할 수 있지만, 이 시점에는 스택에 있던 지역 변수들은 더 이상 값을 유지하지 못합니다. 따라서 내부 클래스가 나중에 올바른 값을 읽으려면 값이 미리 고정되어 있어야 합니다.
- 즉, 로컬 내부 클래스 객체를 생성하기 전에 값이 확정되어 있어야 합니다. 필요하다면 일반(non-final) 변수를 final 변수에 복사한 뒤, 이 final 변수를 내부 클래스에서 사용하면 됩니다.
참고: Java 8부터의 변화
Java 8부터는 명시적으로 final로 선언하지 않아도, 값이 한 번만 할당되는 '사실상 final(effectively final)' 변수라면 내부 클래스에서 자유롭게 접근할 수 있습니다. 다만 값이 재할당되면 컴파일 오류가 발생합니다.
예제 코드
class MainClassTest {
private int x = 10;
public void sampleMethod() {
final int y = 20;
class MethodLocalInnerClassTest {
public void accessMainClassVar() {
System.out.println(x);
// final 지역 변수에 접근
System.out.println(y);
}
}
MethodLocalInnerClassTest inner = new MethodLocalInnerClassTest();
inner.accessMainClassVar();
}
}
// Test.java
public class Test {
public static void main(String args[]) {
MainClassTest test = new MainClassTest();
test.sampleMethod();
}
}
실행 결과
10 20
위 예제에서 내부 클래스는 외부 클래스의 인스턴스 변수 x와 메소드 내의 final 지역 변수 y 모두 문제없이 읽어 출력합니다. 만약 y가 final이 아니고 메소드 종료 후 값이 변경된다면, 내부 클래스가 참조하는 값의 일관성을 보장할 수 없기 때문에 컴파일러는 이를 허용하지 않습니다.