[Java] final

고병갑·2025년 9월 23일

java study

목록 보기
9/10

java에서의 final 키워드는 한 번 정해지면 바꿀 수 없다는 의미를 가짐
하지만 사용되는 위치에 따라 의미가 조금씩 달라짐

1. 변수

final를 변수에 사용하면 값을 변경할 수 없는 상수가 됨
한번 초기화되면 이후 다시 값을 대입 불가능함

public class Example {
    public static void main(String[] args) {
        final int number = 10;
        // number = 20; // 컴파일 에러 발생
    }
}

원시타입(primitive) 👉 값 자체 변경 불가
참조타입(object) 👉 참조(주소)는 바꿀 수 없지만 객체 내부 상태는 변경 가능

final StringBuilder sb = new StringBuilder("Hello");
sb.append(" World");   // 내부 값 변경은 가능
// sb = new StringBuilder("Hi"); // 불가능

2. 메소드

오버라이딩이 금지됨. 즉 상속받은 클래스가 해당 메소드를 재정의 할 수 없음

class Parent {
    public final void show() {
        System.out.println("부모 메서드");
    }
}

class Child extends Parent {
    // @Override
    // public void show() { } // 컴파일 에러 (final이라 오버라이드 불가)
}

3. 클래스

상속 자체를 금지됨
ex) java.lang.String, java.lang.Math

final class MyFinalClass { }

// class SubClass extends MyFinalClass { } // 불가능

4. static final

static 과 함께 사용하면 전역 상수로 활용됨

public class Constants {
    public static final double PI = 3.14159;
    public static final String APP_NAME = "MyApp";
}

final 필드와 생성자 초기화

final 필드는 반드시 선언 시점 또는 생성자에서 한 번만 초기화할 수 있음
static final은 클래스 로딩 시점에 초기화 → 상수(Constant) 용도로 사용됨
final 필드는 초기화 이후 값 변경 불가하므로 불변 객체(Immutable Object) 설계의 핵심 도구

class Person {
    private final String name;
    private final int age;

    // 생성자에서 초기화
    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

final vs effectively final (java 8 이상)

java 8부터는 final 키워드를 명시하지 않아도 값이 한번만 할당된 지역 변수는 컴파일러가 final처럼 취급 (effectively final)
주로 람다식이나 익명 클래스에서 사용 가능

public void run() {
    String message = "Hello"; // effectively final
    Runnable r = () -> System.out.println(message);
    r.run();
}

final과 멀티스레드

final 필드는 객체 생성이 완료된 후에만 접근 가능하므로 초기화 안정성 (Initialization Safety)을 보장
final 필드를 가진 객체는 다른 스레드가 생성자 실행이 끝난 후 접근할 때 항상 올바른 값을 읽을 수 있음
이 특성 때문에 final은 동시성 프로그래밍에서 매우 중요함

정리

final 변수 :
값 재할당 불가,
원시 타입 👉 값 변경 불가
참조 타입 👉 참조 변경 불가 (내부 상태는 변경 가능)

final 메소드 : 오버라이딩 불가, API 안정성 보장
final 클래스 : 상속 불가, 불변 객체나 보안성 강화 목적

+ final 관련 openjdk 에서의 언급 (가이드)

Method parameters and local variables should not be declared final unless it improves readability or documents an actual design decision.
Fields should be declared final unless there is a compelling reason to make them mutable.
Motivation
Writing out modifiers where they are implicit clutters the code and learning which modifiers are implicit where is easy.
Although method parameters should typically not be mutated, consistently marking all parameters in every methods as final is an exaggeration.
Making fields immutable where possible is good programming practice

메소드 매개변수와 로컬 변수는 가독성을 향상하거나 실제 디자인 결정을 문서화하는 경우를 제외하고 final로 선언하면 안된다.

필드는 변경 가능한 필드를 만들어야 하는 강력한 이유가 없는 한 반드시 final 로 선언되어야함.

암시적인 경우에만 수식어를 작성하는 것은 코드를 혼란스럽게 만들며 어디에서 어떤 수식어가 암시적인 지 학습하는 것은 쉽습니다.

일반적으로 메소드 매개변수는 일반적으로 변경되지 않지만 모든 메소드의 모든 매개변수를 final로 지정하는 것은 과장입니다.

필드를 변경할 수 없으면 불변으로 만드는 것은 좋은 프로그래밍 실천입니다.

👉 정리해보자면
Method parameters / local variables

  • 특별한 이유(가독성 향상, 디자인 의도 문서화)가 아니면 final 선언하지 않음

Fields

  • 특별한 사유가 없는 한 무조건 final로 선언하는 것이 바람직함
  • 불변성 확보 → 가독성, 안정성, 동시성에서 유리
profile
노력 naver 배신🔥

0개의 댓글