우테코를 진행하며 final의 중요성에 대해 많은 언급을 받았습니다.
저는 final은 불변하게 만들어주는 키워드이다!!로만 이해를 하고 사용을 하고 있었습니다. 그러던중 과연 final은 언제 붙여주는 것이 좋을까?? 라는 의문이 들었고, 이에 대해 학습을 하고 정리를 해보고자 합니다.
final은 무엇인가?
In the Java programming language, the final keyword is used in several contexts to define an entity that can only be assigned once.
위키피디아에서는 Java의 final을 다음과 같이 한 번만 할당
할 수 있는 엔티티를 정의할 때 사용하는 키워드라고 설명하고 있습니다.
변하지 않는 것이 아니라 한 번만 할당...??같은말인가??라고 생각하실 수 있습니다.
하지만 둘의 뜻은 엄연히 다른 말이며 final을 정확하게 말하면 불변하게 만들어 주는 것이 아닌 재할당을 금지하는 것입니다.
이러한 final을 적용할 수 있는 내용에 대해 하나씩 알아보겠습니다.
1. final변수
1.1. 원시타입
public static void main(String[] args) throws IOException {
final int number = 0;
number = 1; // java: cannot assign a value to final variable number
}
원시 타입의 변수에 final로 선언하면 한번 초기화된 변수는 변경할 수 없는 상수값이 됩니다.
만약 변경을 하려고 시도할 시 IntelliJ에서 오류를 잡아주며, 그래도 강제로 실행할 시 java: cannot assign a value to final variable number
에러를 띄워줍니다.
1.2. 객체타입
public static void main(String[] args) throws IOException {
final Coffee coffee = new Coffee("아메리카노");
coffee = new Coffee("키푸치노");
coffee.setName("카페라떼"); // 객체의 내부 필드값은 변경 가능
}
final 키워드가 붙은 객체 변수는 인스턴스의 참조 값이 지정된 이후 새로운 참조 값으로 재지정이 불가합니다. 하지만 연결된 객체의 필드 값들은 변경이 가능합니다.
연결된 객체가 불변(immutable)은 아닙니다!!
1.3. 메서드 매개변수
public class Coffee {
private String name;
public void setName(final String name) {
this.name = name;
}
}
메서드의 매개변수에 final키워드를 붙여줄 경우 해당 메서드 내에서 변수 값을 변경할 수 없습니다.
1.4. 맴버 변수
멤버변수에 final이 붙는 경우 상수 값이 되거나 한번만 쓸 수 있는 필드가 됩니다. 이러한 final이 붙은 멤버 변수들은 생성자 메서드가 끝나기 전에 초기화를 마쳐야합니다.
static이 붙은 상수와 붙지 않은 인스턴스 변수의 차이는 다음과 같습니다.
1.4.1. 상수 (static final)
static final int STANDARD = 5;
상수 값들은 값과 함께 선언시 클래스 로드시 한번만 실행이 되는 정적 초기화 블록
에서 초기화됩니다.
1.4.2. final 인스턴스 변수
public class Coffee {
private final String name;
public Coffee(final String name) {
}
}
final이 붙은 인스턴스 변수는 값과 함께 선언을 하거나, 생성자에서 선언을 해줘야합니다.
2. final 메서드
public class Coffee {
public final void printBeans() {
System.out.println("콜롬비아 원두");
}
}
public class Americano extends Americano {
public void printBeans() { } // override불가
}
메서드를 final로 선언할 경우 해당 클래스를 상속받은 클래스에서는 final로 선언된 메서드를 재정의(override)가 불가능해집니다. side-effect가 있으면 안 되는 자바 코어 라이브러리와 같이 구현한 코드의 변경을 원하지 않을 때 사용합니다.
3. final 클래스
public final class Coffee { }
public class Americano extends Americano { } // 상속 불가
클래스에 final이 붙을 경우 해당 클래스는 상속이 불가능해집니다. 이러한 final클래스의 경우 Util형식의 클래스나 여러 상수값을 모아둔 constant클래스에 사용합니다.
나만의 final 키워드 기준
- 클래스 변수
가능하면 final을 붙이자. - 인스턴스 변수
생성자 내부에서 초기화 할 수 있으면 final을 붙이자. - 메서드의 매개변수
매개변수에 붙는 final의 경우 원시타입은 재할당을 막을 수 있지만, 그 외의 타입의 경우 내부 필드값의 변경을 막지 못한다. 그리하여 원시타입에는 final을 붙이고 그 외에는 붙이지 않는다. - 메서드 내부의 변수
재할당을 금지할 변수의 경우 final을 붙이자.