[260521]final - 불변값

이상민·2026년 5월 21일

Spring

목록 보기
13/59

목차

final

final은 값 변경불가 또는 참조 변경불가를 의미하며 어디에 붙이냐에 따라 그 역할이 다르다.

1. 변수에서의 final

final int a = 100;
a = 200; //변경불가

변수에서의 final은 변수의 값을 한번만 설정할 수 있으며, 그 후 변경할 수 없다.

2.클래스에서의 final

final class Animal {
    void sound() {
        System.out.println("Animal sound!");
    }
}

class Dog extends Animal {} //상속불가

클래스에 final을 사용하면 해당 클래스를 다른 클래스가 상속할 수 없다.

3.메서드에서의 final

class Parent {
    final void show() {
        System.out.println("Hello from Parent");
    }
}

class Children extends Parent {

	@Override
    void show() { //재정의 불가
        System.out.println("Hello from Child");
    }
}

매서드에서 final로 선언할경우 자식 클래스에서 해당 메서드를 오버라이딩 할 수 없다.

상수(Constant)

상수는 한 번 값이 정해지면 변경되지 않는 값을 의미한다.
Java에서는 이러한 상수들을 대문자로 표기하며, 단어 사이는 _로 구분한다.
또한, 프로그램 실행중 절대 변경되어서는 안되기 때문에 static final을 사용하여 선언한다.

상수의 예시

public class Circle {

    static final double PI = 3.14159; //상수
}
System.out.println("파이상수: " + Circle.PI);

PI(원주율)의 경우엔 원의 둘레나 넓이를 구할때 필수로 사용되고 그 값 또한 고정되어 있기 때문에 상수로 표현하는것이 적절하다.

static final을 사용하는 이유

static final을 사용하는 이유는 간단하다.
상수를 선언할때는 위의 PI(원주율)예시와 같이 여러 곳에서 공통적으로 사용할 목적으로 선언한다.

이러한 인스턴스 변수를 static없이 선언할 경우 인스턴스마다 PI값이 중복으로 저장되기때문에,

class Circle {
	final double PI = 3.14159;
}

Circle c1 = new Circle();
Circle c2 = new Circle();
Circle c3 = new Circle();

static을 붙이지 않는다면 위 코드를 실행했을시, c1, c2, c3 내부에 각각 PI값이 따로 저장되어 메모리 낭비가 발생하게 된다.

불변객체(Immutable Object)

불변객체는 객체 상태를 외부에서 바꿀 수 없도록 설계한 객체를 말한다.
예를 들어 아래와 같은 코드를 작성한다면,

class Radius {
    private final List<Double> radius = new ArrayList<>();
}
.
.
.
radius.getRadius().add(3.8);

이와 같이 final로 선언되어 있어도 내부 내용이 변경될 수 있기 때문에 완전한 불변객체라 할 수 없다.


때문에, 완전히 불변한 객체를 만들기 위해서는

  • 필드 private final 선언
  • Setter 구현하지 않음
  • 필요한 값은 생성자를 통해 초기화
  • 변경이 필요하면 새로운 객체를 생성
    과 같은 방식으로 설계해야 한다.

불변객체 활용 예시

public final class Circle { //클래스에 final 선언 (상속 방지)
    
    private static final double PI = 3.14159; //상수는 private static final로 선언
    private final double radius; //필드를 private final로 선언

    public Circle(double radius) {
        this.radius = radius;
    }

    public double getRadius() {
        return radius;
    }

    public double getArea() {
        return PI * radius * radius;
    }

    public double getPerimeter() {
        return 2 * PI * radius;
    }
}

이런식으로 객체는 private + final로 선언하고 생성자와 같은 메서드들은 public으로 설정한다.
private final radius는 생성이후에 변경이 불가하며, setter또한 없어 외부 수정이 불가능하다.
마지막으로 final class로 상속으로 인한 변경을 방지한다.

값을 변경해야 하는 경우

불변객체의 값을 변경해야 하는 경우엔, 기존 객체의 상태를 직접 변경할 수 없기 때문에 새로운 객체를 생성해야 한다.
생성자를 새로 호출하거나 아래 코드와 같은 기능을 활용할 수 있다.

public final class Circle {
    public static final double PI = 3.14159;
    private final double radius;

    public Circle(double radius) {
        this.radius = radius;
    }

    //다른 반지름을 가진 새로운 Circle 생성
    public Circle changeRadius(double newRadius) {
        return new Circle(newRadius); //생성자 호출: 기존 객체 변경 X, 새 객체 생성
    }
}
Circle c1 = new Circle(5);
Circle c2 = c1.changeRadius(10);

이 경우, c1은 반지름 5를 유지하고 c2는 반지름 10인 새로운 객체로서 생성되었다.

profile
백앤드 개발 브이로그

0개의 댓글