[java] java final 키워드

Goal

  • final 키워드의 사용법을 이해할 수 있다.
  • final, finally, finalize의 차이를 구분할 수 있다.

final 클래스

final이 클래스 이름 앞에 사용되면 클래스를 상속받을 수 없음 을 지정한다.

final class FinalClass {
  ...
}
class DerivedClass extends FinalClass { // 컴파일 오류
  ...
}
  • FinalClass를 상속받아 DerivedClass를 만들 수 없다.

final 메서드

메서드 앞에 final 속성이 붙으면 이 메서드는 더 이상 오버라이딩할 수 없음 을 지정한다.

public class SuperClass {
  protected final int finalMethod() { ... }
}
class DerivedClass extends SuperClass { // SuperClass를 상속 받음
  protected int finalMethod() { ... } // 컴파일 오류
}
  • 자식 클래스가 부모 클래스의 특정 메서드를 오버라이딩하지 못하게 하고 무조건 상속받아 사용하도록 하고자 한다면 final로 지정하면 된다.

final 필드, 상수 정의

자바에서 상수를 정의하는 방법: 필드 멤버에 final 키워드를 덧붙여 상수를 정의한다.

public class FinalFieldClass {
  final int ROWS = 10; // 상수 정의, 이때 초깃값(10)을 반드시 설정

  void f() {
    int[] intArray = new int[ROWS]; // 상수 활용
    ROWS = 30; // 컴파일 오류. final 필드 값은 상수으므로 변경할 수 없다.
  }
}
  • final로 상수 필드를 정의할 때 선언 시에 초깃값을 지정 해야 한다.
  • 상수 필드는 한 번 정의되면 값을 변경할 수 없다.
  • final 키워드만을 사용하여 상수를 만들면 FinalFieldClass의 객체들만 사용할 수 있는 상수가 된다.

프로그램 전체에서 공유하여 사용할 수 있는 상수

  • final 키워드 + static
  • Ex) public static final
class ShareClass {
  public static final double PI = 3.141592653589793;
}
/* ShareClass 내에서의 사용 */
double area = PI * radius * radius;
/* 다른 클래스에서의 사용 */
double area = ShareClass.PI * radius * radius;

final, finally, finalize의 차이

final 키워드

변수나 메서드 또는 클래스가 ‘변경 불가능’하도록 만든다.

  • 원시(Primitive) 변수에 적용 시
    • 해당 변수의 값은 변경이 불가능하다.
  • 참조(Reference) 변수에 적용 시
    • 참조 변수가 힙(heap) 내의 다른 객체를 가리키도록 변경할 수 없다.
  • 메서드에 적용 시
    • 해당 메서드를 오버라이드할 수 없다.
  • 클래스에 적용 시
    • 해당 클래스의 하위 클래스를 정의할 수 없다.

finally 키워드

try/catch 블록이 종료될 때 항상 실행될 코드 블록을 정의하기 위해 사용한다.

  • finally는 선택적으로 try 혹은 catch 블록 뒤에 정의할 때 사용한다.
  • finally 블록은 예외가 발생하더라도 항상 실행된다.
    • 단, JVM이 try 블록 실행 중에 종료되는 경우는 제외한다.
  • finally 블록은 종종 뒷마무리 코드를 작성하는 데 사용된다.
  • finally 블록은 try와 catch 블록 다음과, 통제권이 이전으로 다시 돌아가기 전 사이에 실행된다.
public static String lem() {
  System.out.println("lem");
  return "return from lem";
}
public static String foo() {
  int x = 0;
  int y = 5;
  try {
    System.out.println("start try");
    int b = y / x;
    System.out.println("end try");
    return "returned from try"
  } catch (Exception ex) {
    System.out.println("catch");
    return lem() + " | returned from catch";
  } finally {
    System.out.println("finally");
  }
}
public static void bar() {
  System.out.println("start bar");
  String v = foo();
  System.out.println(v);
  System.out.println("end bar");
}
// 출력
public static void main(String[] args) {
  bar();
}
start bar
start try
catch
lem
finally
return from lem | returned from catch
end bar
  • 출력 3~5번 줄까지를 보면, 함수 호출 내부에 있는 return문을 포함해서 catch 블록이 완전히 실행된 후에 실제로 반환한다.

finalize() 메서드

쓰레기 수집기(GC, Garbage Collector)가 더 이상의 참조가 존재하지 않는 객체를 메모리에서 삭제하겠다고 결정하는 순간 호출된다.

  • Object 클래스의 finalize() 메서드를 오버라이드해서 맞춤별 GC를 정의할 수 있다.
    protected void finalize() throws Throwable {
    /* 파일 닫기, 자원 반환 등등 */
    }