JAVA의 가장 기본이 되는 내용

final

cwchoiit 2024. 3. 27. 16:45
728x90
반응형
SMALL

final 키워드는 이름 그대로 끝! 이라는 뜻이다. 변수에 final이 붙으면 더이상 값을 변경할 수 없다. 정의를 모르는게 아니고 약간 헷갈릴 수 있는 부분들이나 알아두면 코드에 더 도움이 되는것들을 적어봤다.

 

다음 코드를 보자.

Final

public class Final {
    private final int value = 10;

    public Final(int value) {
        this.value = value;
    }
}

이 코드는 에러를 발생시킨다. 왜냐하면 'value'라는 변수에 final 키워드가 붙었고 선언과 동시에 초기화를 해줬다. 그럼 그 이후에 어디서도 이 값을 변경할 수 없는데 생성자에서 받은 값을 대입하려고 하고 있기 때문이다. 그래서 저 코드는 다음과 같이 수정할 수 있다.

public class Final {
    private final int value;

    public Final(int value) {
        this.value = value;
    }
}

value라는 변수를 final로 선언했지만 초기화하지 않은 경우 생성자를 통해서 초기화하든 어디서든 딱 한번은 초기화를 할 수 있다.

그럼 여기서 다음 코드를 보자.

 

Final

public class Final {
    private final int value = 10;

    public int getValue() {
        return value;
    }
}

 

FinalMain

public class FinalMain {
    public static void main(String[] args) {
        Final f = new Final();
        Final f2 = new Final();
        Final f3 = new Final();

        System.out.println("f = " + f.getValue());
        System.out.println("f2 = " + f2.getValue());
        System.out.println("f3 = " + f3.getValue());
    }
}

 

지금 이렇게 Final 이라는 클래스가 있고 그 클래스의 인스턴스 변수 valuefinal로 선언된 변수이다.

이 클래스의 인스턴스를 3개 만들고 해당 인스턴스가 가지는 value값을 출력해보면 다음 결과가 나온다.

실행결과:

f = 10
f2 = 10
f3 = 10

 

그리고 이 세개의 인스턴스도 마찬가지고 앞으로 생성될 모든 인스턴스 역시 value라는 값은 무조건 10일것이다.

그럼 인스턴스가 새로 생성될 때마다 힙 영역에 그 인스턴스가 올라가는데 메모리 낭비가 되지 않을까? 맞다. 그래서 이럴 때 사용하면 좋은 것이 바로 static이다. 

 

static final

왜냐하면 static으로 선언된 변수를 생각해보면 static 영역에 들어가고 오로지 한 개만 존재한다. 그리고 값은 변하지 않는다 왜냐? final로 선언했으니까.

이 말은 필드에 final + 필드 초기화를 사용하는 경우 static을 붙여서 사용하는 것이 효과적이다.

그리고 이렇게 static final로 선언하면 언제라도 변경되지 않는 유일한 수가 되는데 이를 Constant(상수)라고 한다.

 

자바에서는 상수를 선언할 때 관례가 있는데 모두 대문자를 사용하고 구분은 _로 한다. 다음 코드가 그 예시가 되겠다.

public class Final {
    public static final double PI = 3.14;
    public static final int MAX_USER = 10000;
}

 

 

참조형에 대한 final

그리고 또 한가지 헷갈리는 것은 참조형 변수에 final 키워드가 붙는 경우에는 해당 변수의 참조값을 더 이상 바꿀 수 없다는 것이지 참조하고 있는 인스턴스, 배열, 리스트 등등의 내부값은 변경이 가능하다.

 

난 이게 항상 헷갈렸는데 다음 코드를 보자.

 

Final

public class Final {
    private int value;

    public int getValue() {
        return value;
    }

    public void setValue(int value) {
        this.value = value;
    }
}

 

FinalMain

public class FinalMain {
    public static void main(String[] args) {
        final Final f = new Final();

        System.out.println(f.getValue());
        f.setValue(20);
        System.out.println(f.getValue());
    }
}

 

Final 클래스의 인스턴스 변수 valuefinal이 아니다. 그리고 main() 메서드에서 Final 인스턴스를 생성할 때 변수에 final이 붙었다.

그러면 당연히 초기화 한 이후로 f라는 변수는 다른 참조값을 가질 수 없고 딱 저 인스턴스가 가지는 참조값만 가질 수 있다.

그러나, f가 가지는 참조값을 쭉 따라가면 인스턴스가 나올것인데 그 인스턴스의 변수를 못바꾸는게 아니다. 그래서 실제로 실행결과는 다음과 같다.

 

실행결과:

0
20

 

다른 예시도 보자. 다음은 ArrayList()에 대한 참조값을 final로 받는 변수다. 이 변수에 당연히 다른 ArrayList() 참조값을 넣으려면 에러가난다. 다음이 그 화면인데 그렇다고 한들 이 list가 참조하는 참조값을 따라가서 List에 원소를 추가하고 빼는것에는 아무런 문제가 없다. (new로 선언하는 것은 참조형 = 힙 영역에 메모리를 차지 = 참조값을 참조 변수에 알려줌)

그저 참조값만 더 이상 변경이 불가능한 것이다. 다음을 보자.

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

        final List<Integer> list = new ArrayList<>();

        System.out.println(list.size());

        list.add(1);
        list.add(2);
        list.add(3);

        System.out.println(list.size());
    }
}

실제로 잘 추가가 되고 사이즈를 찍어보면 실행결과는 다음과 같다.

실행 결과:

0
3

 

 

클래스와 메서드에 final

클래스에 final이 붙으면 상속이 끝!

메서드에 final이 붙으면 오버라이딩 끝!

728x90
반응형
LIST

'JAVA의 가장 기본이 되는 내용' 카테고리의 다른 글

상속 (Part.2)  (0) 2024.03.28
상속 (Part.1)  (0) 2024.03.28
자바 메모리 구조 ✨  (0) 2024.03.27
캡슐화  (0) 2024.03.26
Class 레벨의 접근제어자  (0) 2024.03.26