[Java 기본]Section 8 - final

우영·2024년 2월 29일

JAVA 기본편

목록 보기
8/13

final 변수와 상수

final - 값이 들어가면 더 이상 바꾸지 못한다.

package final1;

public class FinalLocalMain {

    public static void main(String[] args) {
        //final 지역 변수
        final int data1;
        data1 = 10; // 최초 한번만 할당 가능
        //data1 = 20; // 컴파일 오류

        //final 지역 변수2
        final int data2 = 10;
        //data2 = 20; // 컴파일 오류
    }

    static void method(final int parameter) {
        //parameter = 20; 컴파일 오류
    }
}

static final 2개가 붙으면 상수이고 대문자로 적는다.

생성자에서 초기화하면 선언할 때 바꿀 수 있다.
필드에서 초기화하면 절대 못 바꾼다.

package final1;
public class FinalFieldMain {
 public static void main(String[] args) {
 //final 필드 - 생성자 초기화
 System.out.println("생성자 초기화");
 ConstructInit constructInit1 = new ConstructInit(10);
 ConstructInit constructInit2 = new ConstructInit(20);
 System.out.println(constructInit1.value);
 System.out.println(constructInit2.value);
 //final 필드 - 필드 초기화
 System.out.println("필드 초기화");
 FieldInit fieldInit1 = new FieldInit();
 FieldInit fieldInit2 = new FieldInit();
 FieldInit fieldInit3 = new FieldInit();
 System.out.println(fieldInit1.value);
 System.out.println(fieldInit2.value);
 System.out.println(fieldInit3.value);
 //상수
 System.out.println("상수");
 System.out.println(FieldInit.CONST_VALUE);
 }
}

해결책 -> 바뀌지 않는 공용 변수


final 상수

상수 = 상수는 변하지 않고 항상 일정한 값을 갖는 수
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 를 자주 사용한다. 물론 특정 위치에서만 사용된다면 다른 접근 제어자를 사용하면 된다.
  • 상수는 중앙에서 값을 하나로 관리할 수 있다는 장점도 있다.
  • 상수는 런타임에 변경할 수 없다. 상수를 변경하려면 프로그램을 종료하고, 코드를 변경한 다음에 프로그램을 다시 실행해야 한다

package final1;

public class ConstantMain1 {
    public static void main(String[] args) {
        System.out.println("프로그램 최대 참여자 수 " + 1000);
        int currentUserCount = 999;
        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);
    }

    private static void process(int currentUserCount) {
        System.out.println("참여자 수:" + currentUserCount);
        if (currentUserCount > 1000) {
            System.out.println("대기자로 등록합니다.");
        } else {
            System.out.println("게임에 참가합니다.");
        }
    }
}

위의 코드는 문제가 있다.

  • 최대 참여자 수가 1000명이 아니라 더 많으면 오류가 발생한다.
  • 코드만 봤을 때 1000의 기준에 대해서 생각해야 한다. 이것을 매직넘버라 한다.

해결

package final1;

public class ConstantMain2 {
    public static void main(String[] args) {
        System.out.println("프로그램 최대 참여자 수 " + Constant.MAX_USERS);
        int currentUserCount = 999;
        process(currentUserCount++);
        process(currentUserCount++);
        process(currentUserCount++);
    }
    private static void process(int currentUserCount) {
        System.out.println("참여자 수:" + currentUserCount);
        if (currentUserCount > Constant.MAX_USERS) {
            System.out.println("대기자로 등록합니다.");
        } else {
            System.out.println("게임에 참가합니다.");
        }
    }
}
  • 매직넘버 해결
  • 최대 참여자 수를 변경하려면 Constant_MAX_USERS의 상수 값만 바꾸면 된다.

final 변수와 참조

변수는 크게 2가지가 있다.

  • 기본형 변수 : 10, 20와 같은 값 보관
  • 참조형 변수 : 객체의 참조값 보관
    • 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);
            data.value = 20;
            System.out.println(data.value);
        }
    }

정리

final 은 매우 유용한 제약이다. 만약 특정 변수의 값을 할당한 이후에 변경하지 않아야 한다면 final 을 사용하자.

  • 예를 들어서 고객의 id 변경하면 큰 문제가 발생한다면 final 로 선언하고 생성자로 값을 할당하자.
  • 만약 어디선가 실수로 id 값을 변경한다면 컴파일러가 문제를 찾아줄 것이다.
package final1;

public class Member {
    private final String id; //final 키워드 사용
    private String name;
    public Member(String id, String name) {
        this.id = id;
        this.name = name;
    }
    public void changeData(String id, String name) {
        //this.id = id; //컴파일 오류 발생
        this.name = name;
    }
    public void print() {
        System.out.println("id:" + id + ", name:" + name);
    }
}

0개의 댓글