final과 상수

김헌규·2025년 6월 2일
post-thumbnail

🔒 final

java에서 final 이란? 단어 의미 그대로 최종적이라는 의미로 한 번 할당되면 변경할 수 없도록 하는 키워드이다. final 키워드는 변수, 메소드, 클래스에 사용될 수 있는 특징을 가진다.


이렇게만 설명하면 이해가 잘 안될 수도 있으니 변수, 메소드, 클래스에 사용되는 예시로 바로 알아보자.

변수

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

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return this.name;
    }

    public int getAge() {
        return this.age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
}


public class Example {

    public static void main(String[] args) {
        // 초기화
        final int num = 1; // 필드 선언 시 값을 주는 방법으로 초기화
        final Person person = new Person("민수", 23); // 생성자로 초기화

        System.out.println(num); // 1
        System.out.println(person.getName()); // "민수"
        System.out.println(person.getAge()); // 23

        num = 2; // 컴파일 에러
        person.setName("철수"); // 이렇게 setter를 통해 객체 내부의 값은 변경 가능!
        person.setAge(25);

        System.out.println(person.getName());
        System.out.println(person.getAge());

        // 하지만 참조값(주소값)을 바꾸는 것은 불가능!
        person = new Person("영수", 29); // 컴파일 에러
    }

}

먼저 변수의 경우 변수에 final을 붙이면 이 변수(필드)는 수정할 수 없다는 의미이다. 먼저 final이 붙은 변수에 초기화를 방법은 값을 할당하거나 생성자를 통해서 값을 주는 방법이 있다.

위의 코드에서 볼 수 있듯이 일반적인 변수의 경우 final이 붙은 변수에 최초로 값을 초기화하고 나서 그 뒤에 값을 변경하면 컴파일 에러가 발생한다.

하지만 생성자로 초기화 한 변수의 경우는 최초로 생성자를 이용하여 객체를 생성한 후 참조 값을 할당한 다음 setter를 통해 인스턴스 변수의 값을 바꿔도 컴파일 에러가 발생하지 않고 값이 변경이 된다. 하지만 다른 객체를 생성하여 변수에 할당되어 있는 참조 값을 변경하게 되면 컴파일 에러가 발생하게 된다.



메소드

public class Parent {
    public final void say() {
        System.out.println("안녕하세요!");
    }
}

public class Child extends Parent {

    @Override // final 메서드는 오버라이드 불가
    public void say() {
        System.out.println("반갑습니다!");
    }

    public void greet() {
        say(); // 부모의 say()를 그대로 사용
        System.out.println("자식 클래스에서 추가 동작");
    }
}

메소드의 경우는 final이 붙은 메소드면 오버라이드가 불가능해진다. 하지만 상속은 가능하다. 그래서 위의 코드처럼 Child의 코드에서 greet 메소드는 say()를 상속받아서 메소드를 실행할 수 있지만 say()를 오버라이드 해서 사용하려고 하면 컴파일 에러가 발생하게 된다.



클래스


public final class Parent {
	...
}


public class Child extends Parent { // 컴파일 에러
	...
}

클래스의 경우 final을 사용하게 된다면 상속받을 수 없게 된다. 위의 코드처럼 부모 클래스에 final 선언이 되어 있으면 자식이 상속받지 못한다는 의미이다.




📌 상수

방금까지 java에서의 final에 대해서 알아보았는데 그러면 상수는 무엇인가? java 사용하면서 final과 같이 상수라는 것을 몇 번 들어봤었는데 이 또한 final처럼 이해하고 있지 않아서 한 번 공부해 보았다.

알아보니 수학에서도 자주 나오던 개념이었다. 수학에서는 수식에서 변하지 않는 값을 일컫는데 java에서 사용하는 상수도 이와 거의 같은 의미이다. java에서의 상수는 프로그램 실행 도중 값이 절대 바뀌지 않는 변수라는 의미이다. 상수는 코드의 가독성을 높이고, 변경되지 않는 값들을 한 곳에서 관리할 수 있어 유지보수에도 용이하다.

예를 들어, 프로그램에서 설정값과 같이 바꾸지 않을 어떤 기준 값이라든지 원주율과 같이 항상 고정된 값이 필요할 경우 사용한다.


public class Constants {
    public static final double PI = 3.14159;
    public static final int MAX_USER = 100;
}

위의 코드처럼 상수는 final과 함께 사용되는데 프로그램 어디서든 Constants.PI와 Constants.MAX_USER와 같이 클래스 이름을 접두사로 붙여 접근할 수 있고 해당 값은 절대 변하지 않는다. 또한 한곳에서 사용한다면 유지 보수도 용이하다.



상수의 특징

  • 변경 불가 : final 키워드로 선언된 변수는 한 번 값이 설정되면 변경할 수 없다.
  • 읽기 전용 : 상수는 초기화된 이후로 읽기 전용이다.
  • 클래스 수준 상수 : static 키워드를 사용하여 클래스 수준에서 선언할 수 있다. 이는 상수를 모든 인스턴스에서 공통으로 사용하도록 한다.
  • 불변성 : 상수의 불변성은 프로그램의 안정성을 높여준다. 예를 들어, 중요한 설정 값들이 변경되지 않도록 한다.


변수와 상수의 차이점


사용 목적

  • 상수(Constant) : 상수는 변경되지 않는 값을 표현할 때 사용된다. 예를 들어, 물리 상수, 수학 상수, 설정 값 등이 해당된다. 상수를 사용함으로써 코드의 가독성과 안정성이 향상된다.
  • 변수(Variable) : 변수는 프로그램의 상태나 데이터를 저장하고 변경할 때 사용된다. 예를 들어, 사용자 입력 값, 계산 결과, 임시 데이터 등이 해당된다.

메모리 사용

  • 상수(Constant) : 상수는 프로그램이 시작될 때 메모리에 로드되고, 프로그램이 종료될 때까지 유지된다. 일반적으로 클래스 로드 시 한 번만 초기화된다. (메소드(클래스) 영역)

  • 변수(Variable) : 변수는 프로그램 실행 중에 필요할 때 메모리에 할당되고, 더 이상 필요하지 않을 때 해제된다. 로컬 변수는 메서드 호출 시 생성되고, 메서드가 종료되면 해제된다. (스택 영역(로컬 변수), 힙 영역(인스턴스 변수))




참조
https://sabarada.tistory.com/148
https://tisue.tistory.com/11
혼자 공부하는 자바

profile
꾸준하게 가자

0개의 댓글