9osari.log
← All posts

[JAVA] final

April 17, 2025 · 4 min read · #java#김영한-java-기본

final 이란?

이름 그대로 ‘끝’ 이라는 뜻이다.

변수에 final 키워드가 붙으면 더 이상 값을 변경할 수 없다.

final 지역변수

final int number;
number = 10; // 최초 한 번은 할당 가능
// number = 20; // 컴파일 오류: 이미 값을 할당했기 때문

//선언과 동시 초기화
fianl int number2 = 20;
// number2 = 30; // 컴파일 오류: 이미 값을 할당했기 때문

final 매개변수

static void print(final int number) {
    // number = 20; // 컴파일 오류
    System.out.println(number);
}

final 필드(맴버 변수)

JAVA에서 final 키워드를 필드(맴버 변수)에 사용하면 값 변경이 불가능한 필드를 만들 수 있다.

그런데, 어디서 값을 초기화하느냐에 따라 사용방식이 달라지며 의미도 달라진다.

생성자를 통한 final 필드 초기화

public class ConstructInit {
    final int value;

    public ConstructInit(int value) {
        this.value = value; // 생성자를 통한 초기화
    }
}
ConstructInit c1 = new ConstructInit(10);
ConstructInit c2 = new ConstructInit(20);
System.out.println(c1.value); // 10
System.out.println(c2.value); // 20

필드에서 바로 초기화

public class FieldInit {
    final int value = 10;
    
    /*public FieldInit(int value) {
        //초기값이 이미 들어가 있으면 생성자로 못넣음
        this.value = value;
        //final은 값이 한번 세팅되면 끝
    }*/
}
FieldInit f1 = new FieldInit();
FieldInit f2 = new FieldInit();
System.out.println(f1.value); // 10
System.out.println(f2.value); // 10

public class FinalFieldMain {

    public static void main(String[] args) {

        //final 필드 - 생성자 초기화
        System.out.println("생성자 초기화");
        ConstructInit constructInit1 = new ConstructInit(10);
        ConstructInit constructInit2 = new ConstructInit(20);
        System.out.println(constructInit1.value);
        System.out.println(constructInit2.value);

        //funal 필드 - 필드 초기화
        System.out.println("필드 초기화");
        FieldInit fieldInit1 = new FieldInit();
        FieldInit fieldInit2 = new FieldInit();
        FieldInit fieldInit3 = new FieldInit();
        System.out.println(fieldInit1.value);
        System.out.println(fieldInit2.value);
        System.out.println(fieldInit3.value);

    }
}

생성자 초기화
10
20
필드 초기화
10
10
10

필드 초기화 vs 생성자 초기화

필드 초기화는 인스턴스마다 같은 값을 계속 생성하므로, 메모리 낭비를 줄이고자 할 경우 static을 붙이는 것이 좋음

static final 상수

public class FieldInit {
    static final int CONST_VALUE = 10;
}

왜 static final을 쓰는지?

매직 넘버(Magic Number)란? 코드 안에 의미 없는 숫자(또는 문자)를 직접 써놓는 걸 말함.

이 숫자가 무슨 의미인지 코드만 봐선 알기 어렵고 여러 군데에서 쓰이면 변경 시 실수 위험도 큼.

if (currentUserCount > 1000) { ... } // ← 1000이 뭘 의미하는지 모름

이럴 때 static final 상수를 사용하면 코드가 더 명확해짐:

if (currentUserCount > Constant.MAX_USERS) { ... }

final 변수와 참조형 타입

기본형 변수에서의 final

final int number = 10;
// number = 20; // 컴파일 오류

참조형 변수에서의 final

final Data data = new Data();
// data = new Data(); // 참조값 변경 불가
data.value = 10;      // 객체 내부 값은 변경 가능
data.value = 20;      // 객체 내부 값은 변경 가능

data는 Data 객체의 주소를 고정한 것. 하지만 data.value 는 final 이 아니기 때문에 자유롭게 바꿀 수 있음!

실무에서의 예시

불변 id 설정

public class Member {
    private final String id;
    private String name;

    public Member(String id, String name) {
        this.id = id;
        this.name = name;
    }

    public void changeData(String id, String name) {
        // this.id = id; // 컴파일 오류
        this.name = name; // 가능
    }
}
public class MemberMain {
  public static void main(String[] args) {
    Member member = new Member("myId", "kim");
    member.print();
    member.changeData("myId2", "seo");
    member.print();
  }
}

id:myId,name:kim
id:myId,name:seo
구분final 의미
기본형 변수값 자체를 변경할 수 없음
참조형 변수참조 주소 변경 불가 (다른 객체로 바꿀 수 없음)
하지만 내부 필드는 변경 가능
실무 활용중요한 값(id 등)은 final로 선언해서 불변성 보장하고, 컴파일 타임에 실수 차단 가능

final은 단순한 키워드가 아니라 의도를 명확히 표현하고, 실수를 줄이는 중요한 설계 도구


> 출처: [김영한의 실전 자바 - 기본편](https://www.inflearn.com/course/김영한의-실전-자바-기본편/dashboard)
···
← PREV [JAVA] 메모리 구조와 static NEXT → [JAVA Questions] 클래스와 객체 예상질문