우선 앞의 아티클과 바로 이어지는 내용이니, 가능한 앞의 내용과 연속해서 확인해 보겠습니다. 우리는 특정 메서드 내부의 로컬 클래스가 선언되었을 때, 이 로컬 클래스가 바깥 메서드의 필드 값이나 메서드를 사용하게 되는 경우 발생할 수 있는 문제점에 대해서 살펴보았습니다. 이를 해결하기 위해서 로컬 클래스가 바깥 메서드의 매개변수 혹은 로컬 변수의 값을 사용하게 되면, 컴파일할 때 해당 값을 로컬 클래스 내부에 복사해 두고 사용하게 된다는 기본 작동 원리를 알아보았죠.
대신 이로 인해서 생기는 제약은 값의 변경이 생기면 안 되기 때문에 JAVA 7까지는 바깥 메서드의 매개변수, 로컬변수 등은 반드시 final 속성을 가진 값들이어야 한다고 했습니다.
또한, JAVA 8 이후에는 반드시 final 속성을 갖지 않은 경우라고 하더라도 로컬 클래스에서 이용이 가능하다고 했습니다. 이 내용에 대해서 이번 아티클에서 구체적으로 확인해 보겠습니다.
우선 JAVA 8부터 갑자기 final 속성이 없는 변수의 사용을 허용한 것은 아닙니다. final이 있든 없든, "로컬 클래스에 복사해서 사용한다"는 원칙은 동일하게 적용됩니다. 차이점은 final 키워드의 유무에 따라 "복사되는 위치"가 변경된다는 점 입니다.
메서드 'method( )' 내부에 선언된 로컬 클래스가 있다고 보겠습니다. 만일 method( )에 선언된 멤버 중에 final 속성의 값을 사용하게 되면 이 값들은 로컬 클래스 내부의 메서드에 복사됩니다. 즉, 로컬 변수로 복사됩니다. 하지만 final 속성이 없는 경우라면, 해당 로컬 클래스의 필드 영역으로 복사됩니다. 물론 복사 위치를 억지로 외우실 필요는 없고, final 키워드가 있을 때처럼 수정이 불가능하다는 사실만 기억하셔도 충분합니다.
예시로 설명드리겠습니다. 아래의 예제는 JAVA 7을 가정합니다.
public class A {
public void method7(final int arg) {
final int localVariable = 1;
// arg = 100;
// localVariable = 100;
class Inner {
public void method() {
int result = arg + localVariable;
}
}
}
}
위에서 바깥 메서드 method7의 파라미터인 arg는 final이 선언되었고, 여기에 로컬 변수인 localVariable도 final로 선언되었습니다. localVariable은 초기화되면서 1이라는 값을 지정했죠. 둘 다 final로 선언된 값이므로, 주석처리 된 라인처럼 arg나 localVariable에 다른 값을 넣을 수 없습니다. arg는 파라미터이기 때문에 인자로 전달되는 경우를 제외하고는 값을 변경할 수 없는 것이죠. 그리고 이를 로컬 클래스 Inner의 method( )에서 사용했습니다.
다음은 똑같은 코드를 JAVA 8에서 final 없이 작성한 것입니다.
public class A {
public void method8(int arg) {
int localVariable = 1;
// arg = 100;
// localVariable = 100;
class Inner {
public void method() {
int result = arg + localVariable;
}
}
}
}
잘 보시면, 모든 코드가 동일하지만 arg와 localVariable에 final 키워드가 삭제되었습니다. 하지만, 여전히 IDE에서 arg나 localVariable의 값을 100으로 수정하려고 하면 컴파일 에러가 발생합니다. 즉, JAVA 7에서 final 키워드를 명시적으로 사용했을 때와 마찬가지로 동일하게 동작하는 것입니다.
(참고) JAVA 8에서 final 키워드를 사용하지 않은 경우, 로컬 클래스에서 어떻게 값이 복사되는지에 대해서도 참고로 설명드리겠습니다. 아래의 예제에서, 바깥 메서드 outterMethod 내부에 LocalClass라는 로컬 클래스를 선언하고 이 로컬 클래스 내부에 method( )가 있다고 가정하겠습니다.
여기서 파라미터 arg1, 변수 var1에는 final이 선언되고 나머지 arg2, var2는 final이 선언되지 않았습니다. 그런데 이 네 개의 변수를 모두 로컬 클래스 내부의 method( )에서 사용할 경우, 실제 컴파일 할 때 어떻게 복사되는지를 알아보겠습니다.
public class A {
void outterMethod(final int arg1, int arg2) {
final int var1 = 20;
int var2 = 40;
class LocalClass {
void method() {
int result = arg1 + arg2 + var1 + var2;
}
}
}
}
이제 위의 코드가 실제 컴파일이 진행되면, LocalClass 안에서는 다음과 같은 형태로 동작을 진행하게 됩니다.
class LocalClass {
/* final 없는 멤버 */
int arg2 = 매개값;
int var2 = 40;
void method() {
/* final 있는 멤버 */
int arg1 = 매개값;
int var1 = 20;
int result = arg1 + arg2 + var1 + var2;
}
}
'Programming > JAVA' 카테고리의 다른 글
중첩 클래스&인터페이스(4) - 중첩 인터페이스 (3) | 2023.04.12 |
---|---|
중첩 클래스&인터페이스(3) - 중첩 클래스의 접근 제한자 5 : 바깥 클래스 참조하기 (0) | 2023.04.11 |
중첩 클래스&인터페이스(3) - 중첩 클래스의 접근 제한자 3 : 로컬 클래스 (0) | 2023.04.09 |
중첩 클래스&인터페이스(3) - 중첩 클래스의 접근 제한자 2 (0) | 2023.04.06 |
중첩 클래스&인터페이스(3) - 중첩 클래스의 접근 제한자 1 (0) | 2023.04.04 |