-
Java 의 Final 키워드언어/자바 2022. 5. 10. 21:08
개요
상속을 통해 기존 코드를 재사용할 수 있지만 때때로 다양한 이유로 확장성에 제한을 설정해야 합니다. final 키워드를 사용하면 정확히 그렇게 할 수 있습니다.
Final Classes
final 로 선언된 클래스는 상속될 수 없습니다. Java 핵심 라이브러리의 코드를 보면 많은 final 클래스들을 볼 수 있습니다. 대표적인 예시로는 String 클래스가 있습니다. 아래의 코드를 살펴보면 Cat 클래스는 final 로 선언되어 있고 이 클래스를 BlackCat 이 상속받고 있습니다. 그 결과 final 클래스인 Cat 을 상속받았다는 컴파일 에러가 발생한 것을 확인할 수 있습니다.
@Getter @Setter public final class Cat { private int wieght; }
public class BlackCat extends Cat { }
The type BlackCat cannot subclass the final class Cat
Final 키워드를 사용함으로써 오해하게 되는 것 중 하나는 final로 선언한 클래스의 객체가 immutable 이라고 생각하게 되는 것입니다. 하지만 객체의 속성을 자유롭게 바꿀 수 있습니다.
Cat cat = new Cat(); cat.setWeight(1); assertEquals(1, cat.getWeight());
좋은 디자인의 규칙을 엄격하게 따른다면 클래스를 신중하게 만들고 안전상의 이유로 final로 선언해야 합니다. 그러나 final 클래스를 생성할 때는 주의해야 합니다.
클래스를 final로 만든다는 것은 다른 어떤 프로그래머도 해당 클래스를 향상시킬 수 없다는 것을 의미합니다. 예를들어 어떤 클래스를 사용하공 ㅣㅆ는데 이에 대한 소스코드도 없는데 해당 클래스의 메소드 중 하나가 문제가 있는 메소드라고 가정해보겠습니다. 만약 해당 클래스가 final 이 아니면 해당 클래스를 상속받아서 override 하는 방법이 있겠지만 final 로 선언되어있기 때문에 해당 메소드를 override 할 수 없습니다. 클래스가 final이면 메서드를 재정의하고 문제를 해결하기 위해 클래스를 확장할 수 없습니다. 즉, 객체지향 프로그래밍의 장점 중 하나인 확장성을 잃게 됩니다.
Final Methods
final 로 선언된 메서드는 override 할 수 없습니다. 클래스를 구성할 때 어떤 메소드가 override 되면 안될 거 같을 땐 final 로 만들면 됩니다. 자바 코어 라이브러리에도 여러 메소드 들이 final 로 구성되어 있습니다. 대표적으로 Thread 클래스에 isAlive() 메소드가 final 로 선언되어 있습니다.
public class Dog { public final void sound() { //... } }
public class BlackDog extends Dog { public void sound() { } }
위의 코드를 살펴보면 Dog 클래스의 sound() 메소드를 final 로 선언한 것을 볼 수 있습니다. 이 때 BlackDog 이 Dog 클래스를 상속하여 sound() 메소드를 override 할 수 있도록 선언해보겠습니다.
해당 코드를 컴파일 하면 아래와 같은 오류가 뜨는것을 확인할 수 있습니다.
Cannot override the final method from Dog sound() method is final and can’t be overridden
Final Variables
변수가 final 로 선언되면 다시 선언될 수 없습니다. 즉, final 변수가 초기화 되면 다른 값으로 변할 수 없습니다.
Final Primitive Variables
primitive 타입 중 하나인 int를 사용해 변수 i 를 선언해보겠습니다.
public void whenFinalVariablesAssign_thenOnlyOnce() { final int i = 0; // ... i = 2; }
결과로 아래와 같은 오류 메시지를 볼 수 있습니다.
The final local variable i may already have been assigned
Final Reference Variables
reference 변수가 final 로 선언되면 마찬가지로 재 할당될 수 없습니다. 하지만 객체가 immutable 하다는 의미가 아닙니다. 객체의 속성값은 자유롭게 바꿀 수 있습니다.
final Cat cat = new Cat(); cat.setWeight(5); cat.setWeight(10); cat = new Cat(); // compile erro
Final Fields
final 로 설정한 필드는 상수가 될 수도 있고 선언된 후 바꿀 수 없는 필드일 수도 있습니다. 네이밍 컨벤션으로 클래스 상수는 대문자여야 하고 각 단어는 _ 로 이어져야 합니다.
static final int MAX_WIDTH = 999;
모든 final 필드는 생성자가 선언되기 전에 초기화 되어야 합니다.
static final 필드는 다음과 같은 상황에서 초기화 될 수 있습니다.
- 위의 예시들 처럼 선언할 때
- static 초기화 블록에서
final 필드는 다음과 같은 상황에서 초기화 될 수 있습니다.
- 선언할 때
- 생성자 안에서
- 인스턴스 초기화 블록에서
그 외의 경우엔 컴파일 에러가 발생합니다.
Final Arguments
final 를 arguments 앞에 붙일 수 있습니다. 이 경우 파라미터로 받은 argument는 메서드 안에서 수정될 수 없습니다.
public void methodWithFinalArguments(final int x) { x = 1; // complie error }
다음과 같이 수정하면 아래와 같은 에러 메시지를 볼 수 있습니다.
The final local variable x cannot be assigned. It must be blank and not using a compound assignment
참고