익명 구현 객체와 final
05 Aug 2024익명 구현 객체에서 사용하는 외부 변수는 final이어야 한다는데, 왜 그런지 알아보자.
익명 구현 객체
익명 구현 객체는 클래스나 인터페이스의 구체적인 구현을 직접 선언하지 않고, 인스턴스를 생성하면서 즉성에서 구현하는 방식이다.
보통 인터페이스나 추상 클래스를 구현할 때 사용되며, 특별한 이름을 갖지 않는 클래스 형태로 작성된다.
final 키워드
final 키워드는 변수, 메서드, 클래스에 사용될 수 있으며, 각기 다른 의미를 가진다.
변수에 final: 값이 한 번만 할당될 수 있다. -> 불변 상수
메서드에 final: 해당 메서드를 오버라이드 할 수 없게 된다.
클래스에 final: 해당 클래스를 상속할 수 없게 된다.
익명 구현 객체와 final
각 개념에 대해 정리했으니, 이 포스팅에 맞는 내용을 알아보자.
익명 클래스 내에서 외부 변수에 접근하려면, 그 외부 변수는 final이거나 사실상 final이어야 한다.
이는 해당 변수가 익명 클래스 내부에서 사용될 때 그 값이 변경되지 않도록 보장하기 위해서이다.
익명 클래스는 외부 클래스의 인스턴스와는 별도로 존재하는 내부 클래스이다.
익명 클래스가 생성될 때, 외부 변수의 값을 캡처하는 방식으로 저장하는데, 이때 중요한 점은 외부 변수의 변경 여부다.
자바는 익명 클래스에서 외부 변수를 사용할 때 해당 변수의 값을 클로저처럼 캡처한다.
왜 그러지? 그냥 참조해서 쓰면 되는거 아닌가?
단순히 참조해서 사용하지 않고 캡처를 해서 사용하는 것은 변수의 수명, 동작의 안정성 및 동시성 문제와 관련이 있다.
자바에서 익명 클래스나 람다 표현식은 클래스의 인스턴스를 동적으로 생성한다.
익명 클래스나 람다는 외부 메서드의 스택 프레임(즉, 메서드가 실행되는 동안만 존재하는 변수들)을 참조할 수 있다.
그럼에도 불구하고 메서드가 종료된 후에도 그 외부 변수를 익명 클래스가 참조할 수 있어야 한다.
이를 위해서는 외부 변수의 값이 메서드 종료 후에도 유지될 수 있어야 한다.
그렇기에 캡처는 이러한 변수를 힙영역에 저장하고, 익명 클래스가 이를 사용할 수 있도록 보장하는 방식이다.
이렇게 저장된 변수는 메서드 실행이 종료된 후에도 계속 존재하며, 익명 클래스나 람다가 실행될 때 참조할 수 있다.
또한 외부 변수를 캡처할 때 그 변수가 final이어야 하는 이유는 변경 불가능성을 보장하기 위해서다.
캡처한 값이 변경된다면 캡처된 값은 여전히 초기 값을 참조하고 있을 것이다.
이러한 상황에서는 동기화 문제나 값이 불일치되는 문제가 생긴다.
(final로 명시되지 않은 변수라도 값이 변경되지 않으면 사실상 final로 간주)