Java, final 변수 또는 멤버 필드
바뀌지 않는 결정적인, 끝이라는 의미를 담긴 final 키워드가 있다.
변수에 final 키워드를 붙이면 값을 변경할 수 없다.
변수 뿐 아니라 final 키워드는 자바 class, method 포함한 여러 곳에서 붙일 수 있다.
변수에 붙이는 final 키워드에 대해 알아본다.
지역 변수 - final
코드로 final 사용 예제를 살펴본다.
FinalMain.java 예제 1
- 변수 decision 선언
- decision 값 할당은 최초 한번만 가능
package finalLocal;
public class FinalMain {
public static void main(String[] args) {
final int decision;
decision = 10; // 최초 한 번만 할당 가능하다.
// decision = 20; // 컴파일 오류, 이미 할당된 데이터로 변경할 수 없다.
}
}
FinalMain.java 예제2
- 변수 초기 값 지정 후 선언
- 초기 값이 지정 된 final 데이터은 변경 불가능
package finalLocal;
public class FinalMain {
public static void main(String[] args) {
final int decision = 10; // 최초 한 번만 할당 가능하다.
// decision = 20; // 컴파일 오류, 이미 할당된 데이터로 변경할 수 없다.
}
}
FinalMain.java 예제3
- 메소드 decisionMethod 작성 후 파라미터로 final 할당
- main() 에서 메소드 호출 시 인수 값 전달 가능(
decisionMethod(10)
). - 메소드 내부에서 할당 된 지역변수 final 값은 변경 불가능
- 메소드 내부에서 호출에서 전달 받은 값은 메소드 종료까지 사용 가능
package finalLocal;
public class FinalMain {
public static void main(String[] args) {
decisionMethod(10);
}
static void decisionMethod(final int data) {
// data = 10; // 컴파일 오류
}
}
클래스 필드(멤버 변수) - final
Init 클래스를 작성하여 필드 (멤버 변수)에서 사용하는 final 에 대해서 알아보도록 한다.
Init.java 예제 - final
- 멤버 변수 final 키워드 붙인 value 선언 후
- 생성자를 통해서 값을 할당
package finalLocal;
public class Init {
final int value; // 생성자 통해서 할당한다.
public Init(int value) {
this.value = value;
}
}
Init.java 예제 - static final 상수
- 멤버 변수 상수로 static final 사용 가능
package finalLocal;
public class Init {
static final int CONST_VALUE = 10000;
final int value = 10000;
public Init(int value) {
// CONST_VALUE = value; // 컴파일 오류, final 변수로 이미 할당되어있음
// this.value = value; // 컴파일 오류, final 변수로 이미 할당되어있음
}
}
final 사용하기
클래스를 생성하여 사용해보도록 한다.
Init.java
package finalLocal;
public class Init {
final int value;
public Init(int value) {
this.value = value;
}
}
Final.java
package finalLocal;
public class Field {
final static int CONST_VALUE = 100;
final int value = 10000;
}
Main.java
package finalLocal;
public class FinalMain {
public static void main(String[] args) {
// Init 초기화
System.out.println("Init 생성자 초기화");
Init construct1 = new Init(365);
Init construct2 = new Init(1000);
System.out.println(construct1.value);
System.out.println(construct2.value);
// Field 필드 초기화
System.out.println("Field 필드 초기화");
Field field1 = new Field();
Field field2 = new Field();
Field field3 = new Field();
System.out.println(field1.value);
System.out.println(field2.value);
System.out.println(field3.value);
// 상수
System.out.println("상수");
System.out.println(Field.CONST_VALUE);
}
}
출력 결과
Init 생성자 초기화
365
1000
Field 필드 초기화
10000
10000
10000
상수
100
생성자 초기화
construct1 생성자를 사용하여 field 초기화 하는 방법으로 각 인스턴스마다 각기 다른 값을 할당하였다. 할당된 final 은 다른 값으로 이제 변경이 불가하다.

힙 영역에는 value 의 값 365 숫자와 1000 담겨 있을 것이다.
필드 초기화
Field 클래스는 선언과 동시에 초기 값을 넣은 값이다.
인스턴스를 생성한 경우 이 멤버 변수는 10000 값이 고정되어 있다.

생성자 초기화와 다르게 필드 초기화는 해당 값을 미리 정해져 있다.
모든 인스턴스가 같은 값을 사용하고 결과적으로 메모리 낭비하게 된다. (내부적으로 최적화가 되어있는 JVM 도 있다.) 개발자 입장에서는 명확한 중복 데이터이고 메모리 낭비이기에 static 영역으로 옮기면 메모리를 아낄 수 있다.
static final
- Field.CONST_VALUE 는 메소드 영역에 속한 static 영역에 있다. final 키워드를 사용한 초기화 값은 변화지 않는다.
- static 선언 시 인스턴스와 무관하게 하나만 존재한다. 앞서 말한 중복과 메모리 낭비를 해결할 수 있다.
불필요한 메모리 낭비를 피하고 데이터 공유가 필요한 경우,
final + 필드 초기화 선언하고 static 키워드를 붙여주는 것이 효과적이다.
