본문 바로가기
자바

final, 상수

by 이상한나라의개발자 2023. 12. 14.

final은 자바 프로그래밍 언어의 키워드로, 다양한 컨텍스트에서 사용될 수 있으며, 그 의미는 사용되는 컨텍스트에 따라 다릅니다.

변수, 메서드, 클래스에서 주로 사용됩니다.

final 키워드 사용 법은 자바의 다형성과 캡슐화 원칙을 강화하고, 불변성(immutability)과 보안을 증진 시키는데 중요한 역할을 합니다. 불변 객체는 스레드 안전(thread-safe)하고, 사이드 이펙트(side-effects)를 줄이며, 코드의 안정성과 예측 가능성을 높입니다.

 

지역 변수에 사용될 경우

final 키워드가 지역 변수에 사용될 때, 해당 변수는 변경할 수 없는 상태가 됩니다. 이는 변수가 선언된 메서드 또는 블록 내에서만 적용됩니다.

 

public void myMethod() {
    final int localNumber = 10;
    // localNumber = 20; // 이 코드는 오류를 발생시킵니다. final 변수는 재할당할 수 없습니다.
}

 

인스턴스 변수에 사용될 경우

인스턴스 변수에 final 키워드를 사용하면, 해당 변수는 객체가 생성될 때 (생성자) 한번만 값을 할당 받을 수 있으며, 이 후에는 변경할 수 없습니다.

 

public class MyClass {
    final int instanceNumber;

    MyClass(int number) {
        instanceNumber = number; // 생성자에서만 할당 가능
    }

    // 이후에 instanceNumber의 값을 변경할 수 없습니다.
}

 

메서드에 사용될 경우

메서드에 final 키워드를 사용하면, 해당 메서드는 하위 클래스에서 오버라이딩 (재정의)할 수 없습니다.

public class MySuperClass {
    public final void show() {
        System.out.println("이 메서드는 오버라이딩될 수 없습니다.");
    }
}

public class MySubClass extends MySuperClass {
    // public void show() { } // 이 코드는 오류를 발생시킵니다. final 메서드는 재정의할 수 없습니다.
}

 

클래스에 사용될 경우

final로 선언된 클래스는 확장(상속)될 수 없습니다. 이는 한 클래스의 모든 메서드는 자동으로 final이 됩니다. 즉 하위 클래스에서 오버라이드 할 수 없습니다. 이는 안전하고 변경 불가능한 클래스를 만들고 싶을 때 사용 됩니다. 예를들에 String 클래스는 final 클래스 입니다.

 

public final class String {
    // 클래스 내부 구현 ...

    public String() {
        // 생성자 구현 ...
    }

    // 다양한 메서드들 ...
}

 

 

public class MyString extends String {
    // 이 클래스는 컴파일되지 않습니다. String은 final 클래스이므로 상속할 수 없습니다.
}

 

 

위의 MyString 클래스는 String 클래스를 상속 받아 확장 하려고 시도하지만 String 클래스는 final 클래스 이므로 허용되지 않으며 컴파일 오류를 발생 시킵니다. 이는 final 클래스의 중요한 특징을 보여주는 예시입니다. final 클래스를 사용하는 이유중 하나는클래스의 불변성을 유지하고 보안 강화를 위해서 입니다. 위의 String 클래스는 불변성을 갖고 있으며 이를 통해 문자열 데이터의 보안과 신뢰성을 보장합니다.

 

상수

상수는 final 키워드와 static 키워드를 함께 사용하여 정의 됩니다. 상수는 변경할 수 없고 고정값 표현이며, 클래스 레벨(메서드영역)에서 관리됩니다. 상수의 이름은 관례상 대문자_대문자 (ex: MAX_SIZE) 로 표현 됩니다.

 

public class Constants {
    public static final int MAX_SIZE = 100; // 상수

    public static void main(String[] args) {
        // Constants.MAX_SIZE = 200; // 이 코드는 오류를 발생시킵니다. 상수의 값은 변경할 수 없습니다.
        System.out.println("MAX_SIZE: " + Constants.MAX_SIZE);
    }
}

 

  • 상수 풀(Constant Pool) : JVM은 클래스 또는 인터페이스에 대한 상수 데이터를 상수 풀이라는 특별한 메모리 영역에 저장합니다. 이 풀 리터럴 값(예:문자열, 숫자 리터럴), 심볼릭 참조(클래스, 인터페이스, 필드, 메서드에 대한 참조) 등 다양한 유형의 상수 정보를 포함 합니다.
  • 컴파일 타임 최적화 : 컴파일 타임에 상수 값이 결정되면, 컴파일러는 이러한 값들을 바이트코드에 직접 삽입할 수 있습니다. 예를 들어 static final int VALUE = 10 과 같은 상수는 사용될 때마다 10 이라는 값으로 바이트코드에 직접 삽입됩니다.
  • 런타임 최적화 : 클래스가 로드되고 초기화될 때, 상수 풀에 저장된 상수는 메모리에 할당되고, JVM은 이러한 상수를 효율적으로 접근하고 관리합니다. 
  • 매직넘버 : 매직넘버란 의미 있는 상수의 이름으로 대체될 수 있는 숫자란 뜻을 가지고 있습니다.

아래 코드에서 number > 10, number < 0 은 해당 코드만 봐서는 이해가 쉽지 않습니다.

어떤 의미인지 와닿지 않기 때문이죠 

 

public class MagicNumber {

    public static void main(String[] args) {

        addShoppingCart(10);
    }
    // 장바구니
    public static void addShoppingCart (final int number) {
        if ( number > 10  || number < 0 ) {
            throw new IllegalArgumentException("장바구니 최대 허용 되지 않습니다.");
        }
    }
}

 

 

아래와 같이 매직넘버를 적용하게 되면 해당 코드가 어떤 역할을 수행하는지 명확하게 구분 됩니다.

 

public class MagicNumber {
    
    public static final int ITEM_MAX_COUNT = 10;
    public static final int ITEM_MIN_COUNT = 0;

    public static void main(String[] args) {

        addShoppingCart(10);
    }
    // 장바구니
    public static void addShoppingCart (final int number) {
        if ( number > ITEM_MAX_COUNT  || number < ITEM_MIN_COUNT ) {
            throw new IllegalArgumentException("장바구니 최대 허용 되지 않습니다.");
        }
    }
}

'자바' 카테고리의 다른 글

내부 클래스 ( inner class ) 란?  (0) 2024.01.02
자바 캐스팅(casting)  (1) 2023.12.15
static  (0) 2023.12.13
자바 메모리 구조  (0) 2023.12.13
Stream & Optional & Parallel Stream  (0) 2023.12.12