Java/문법

[JAVA 중급 스터디 - 6회차] final

soowitty 2024. 3. 20. 14:08

final

final 키워드

  • 처음 정의된 상태가 변하지 않도록 보장한다.
  • class, method, 변수 등 여러 곳에 붙을 수 있다.

final

final + 지역변수

  • final을 지역 변수에 설정할 경우, 최초 한번만 할당 가능
  • 이후에 변수의 값을 변경하면 컴파일 오류 발생
  • final 지역변수를 선언시 바로 초기화한 경우, 이미 값이 할당되없으므로 이후에 값 재할당 불가능

final + 매개변수

  • 매개변수에 final이 붙으면 메서드 내부에서 매개변수 값의 변경이 불가능
    • 메서드 호출시점에 사용된 값이 끝까지 사용됨
    • public class FinalLocalMain { public static void main(String[] args) { //final 지역 변수1 final int data1; data1 = 10; //최초 한번만 할당 가능 //data1 = 20; //컴파일 오류 //final 지역 변수2 final int data2 = 10; //data2 = 20; //컴파일 오류 method(10); } //final 매개변수 static void method(final int parameter) { //parameter = 20; 컴파일 오류 } }

final + 멤버변수(필드)

  • final을 필드에 사용할 경우, 해당 필드는 한번만 초기화 가능
  • final 필드를 초기화하는 방법
    • 아래 두가지 방법 중 한가지를 사용하면 된다.
    • 생성자 초기화
    • package final1; // final 필드 - 생성자 초기화 public class ConstructInit { final int value; public ConstructInit(int value) { this.value = value; } }
    • 필드 초기화
    • package final1; // final 필드 - 필드 초기화 public class FieldInit { static final int CONST_VALUE = 10; final int value = 10; }
package final1;

public class FinalFieldMain {
    public static void main(String[] args) {

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

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

        // 상수
        System.out.println("상수");
        System.out.println(FieldInit.CONST_VALUE); //10

    }
}
  • ConstructInit : 생성자 초기화
    • 각 인스턴스마다 final 필드에 다른 값 할당 가능
      • 이후 변경은 불가능
  • FieldInit : 필드 초기화
    • 모든 인스턴스가 같은 값을 가짐
      image
    • FieldInit 인스턴스의 모든 value 값이 10이 됨
    • 필드 초기화는 필드의 코드에 해당 값이 미리 정해져 있기 때문
    • 모든 인스턴스가 같은 값을 사용 -> 메모리 낭비
      • JVM에 따라서 내부 최적화를 시도할 수 있다. 하지만, 메모리 낭비를 떠나서 같은 값이 계속 생성되는 것은 중복이다.
        • -> static 영역을 사용하자.
  • FieldInit.MY_VALUE : static final
    • static 영역에 존재
    • final 키워드를 사용했기 때문에 초기화 값이 변하지 않음
    • static 영역은 단 하나만 존재. -> MY_VALUE 변수는 JVM 상에 하나만 존재 -> 중복, 메모리 비효율 해결

✏️ 필드에 final + 필드 초기화를 사용하는 경우, static을 붙여서 사용하자.

 

final static

  • 상수(constant) : 변하지 않고, 항상 일정한 값을 갖는 수.
    • Java에서, 단 하나만 존재하며 변하지 않는 고정된 값을 상수라고 칭한다.
  • Java 상수의 특징
    • static final 키워드를 사용
    • 대문자를 사용, _(언더스코어)로 구분
      • 일반적인 변수와 구분하기 위함
    • 필드를 직접 접근해서 사용
      • 상수의 목적은 고정된 값 자체를 사용하는 것! (기능이 목적이 아님)
      • 상수의 값 변경은 불가능하다. 따라서, 필드에 직접 접근해도 데이터가 변하는 문제가 발생하지 않는다.
    package final1;

public class Constant {

    // 수학 상수
    public static final double PI = 3.14;

    // 시간 상수
    public static final int HOURS_IN_DAY = 24;
    public static final int MINUTES_IN_HOUR = 60;
    public static final int SECONDS_IN_MINUTE = 60;

    // 애플리케이션 설정 상수
    public static final int MAX_USERS = 1000;
}
  • 일반적으로 상수는 애플리케이션 전반에서 사용됨. -> public 사용
    • 특정 위치에서만 사용하는 경우, 다른 접근 제어자를 사용
  • 상수는 런타임에 변경 불가능
    • 변경하려면 프로그램을 종료해야 함

final 변수와 참조

  • final + 기본형 변수 : 실제 값 변경 불가능
  • final + 참조형 변수 : 실제 값 변경 가능, 주소값은 변경 불가능
package final1;

public class FinalRefMain {

    public static void main(String[] args) {

        final Data data = new Data();
        //data = new Data(); //final 변경 불가 컴파일 오류

        //참조 대상의 값은 변경 가능
        data.value = 10;
        System.out.println(data.value); //10
        data.value = 20;
        System.out.println(data.value); //20

    }
}

public class Data {
    public int value;
}