목차
자바에서 final / finally / finalize 란 무엇인가??
자바(Java)를 학습하다 보면 final / finally / finalize라는 비슷한 용어를 접하게 됩니다.
이름은 비슷하지만, 각자 완전히 다른 역할을 수행하며, Java 프로그래밍의 핵심적인 부분을 담당합니다. 이 세 가지 키워드를 제대로 이해하고 활용하는 것은 효율적이고 안정적인 Java 애플리케이션 개발에 필수적입니다.
이번 글에서는 각 개념의 차이점과 사용법, 그리고 주의해야 할 사항을 예제와 함께 자세히 살펴보겠습니다.
1. final 키워드란?
1.1 개념
final 키워드는 변수, 메서드, 클래스에 사용될 수 있으며, 각 경우마다 의미가 다르게 적용됩니다.
final은 Java에서 "최종적인" 또는 "변경 불가능한" 상태를 나타내는 키워드입니다. final은 클래스, 메서드, 변수에 적용될 수 있으며, 각 경우에 따라 의미와 역할이 조금씩 다릅니다.
✅ 변경할 수 없도록(수정 불가능) 만드는 키워드입니다.
1.2 final의 사용 방법
final 사용 대상 | 설명 |
변수 | 값을 변경할 수 없음 (상수) |
메서드 | 오버라이딩(재정의) 불가능 |
클래스 | 상속 불가능 (확장 불가) |
1.3 final 변수 (값 변경 불가능)
- 정의: final 변수는 한 번 값이 할당되면 더 이상 변경할 수 없는 변수를 의미합니다.
- 특징:
- 변수의 불변성을 보장하여 데이터의 무결성을 유지합니다.
- 상수(Constant)를 정의할 때 사용됩니다.
- 종류:
- static final 변수 (클래스 상수): 클래스 로딩 시점에 초기화되며, 모든 인스턴스에서 공유되는 상수입니다.
- 인스턴스 final 변수: 객체 생성 시점에 초기화되며, 각 인스턴스마다 다른 값을 가질 수 있습니다.
class MyClass {
private static final double PI = 3.14159; // 클래스 상수
private final int value; // 인스턴스 final 변수
public MyClass(int value) {
this.value = value;
}
public double getArea(int radius) {
return PI * radius * radius;
}
public int getValue() {
return value;
}
}
✅설명:
- PI는 static final로 선언되었으므로, 클래스 로딩 시점에 초기화되고, 모든 MyClass 인스턴스에서 공유되는 상수입니다.
- value는 인스턴스 final 변수이므로, 객체 생성 시점에 초기화되고, 각 MyClass 인스턴스마다 다른 값을 가질 수 있습니다. 하지만 한 번 초기화된 후에는 값을 변경할 수 없습니다.
✅활용: 상수 정의, 불변 객체 구현, 데이터 무결성 유지 등 다양한 용도로 활용됩니다.
1.4 final 메서드 (오버라이딩 불가능)
- 정의: final 메서드는 하위 클래스에서 오버라이딩될 수 없는 메서드를 의미합니다.
- 특징:
- 메서드의 동작을 하위 클래스에서 변경하는 것을 방지합니다.
- 다형성을 제한하여 코드의 예측 가능성을 높입니다.
class ParentClass {
public final void display() {
System.out.println("This is a final method.");
}
}
class ChildClass extends ParentClass {
// 아래 코드는 컴파일 에러를 발생시킵니다.
// @Override
// public void display() { ... }
}
✅설명: ParentClass의 display() 메서드는 final로 선언되었으므로, ChildClass에서 display() 메서드를 오버라이딩할 수 없습니다. 이는 ParentClass의 display() 메서드의 동작을 보장하고, 하위 클래스에서 예상치 못한 변경을 방지합니다.
✅활용: 특정 메서드의 동작을 반드시 유지해야 하는 경우에 사용됩니다. 예를 들어, 보안 관련 로직이나 핵심 알고리즘을 포함하는 메서드를 final로 선언하여 하위 클래스에서 실수로 변경하는 것을 방지할 수 있습니다.
1.5 final 클래스 (상속 불가능)
- 정의: final 클래스는 더 이상 상속될 수 없는 클래스를 의미합니다.
- 특징:
- 클래스의 확장을 제한하여 예상치 못한 동작을 방지합니다.
- 컴파일러 최적화를 통해 성능 향상을 기대할 수 있습니다.
final class ImmutableClass {
private final int value;
public ImmutableClass(int value) {
this.value = value;
}
public int getValue() {
return value;
}
}
// 아래 코드는 컴파일 에러를 발생시킵니다.
// class SubClass extends ImmutableClass { ... }
✅설명: ImmutableClass는 final로 선언되었으므로, 다른 클래스가 ImmutableClass를 상속할 수 없습니다. 이는 ImmutableClass의 동작을 예측 가능하게 하고, 예상치 못한 변경을 방지합니다.
✅활용: 불변 클래스(Immutable Class)를 만들 때 유용하게 사용됩니다. 불변 클래스는 한 번 생성된 후에는 내부 상태가 변경되지 않는 클래스를 의미하며, 스레드 안전성을 확보하고 프로그램의 안정성을 높이는 데 기여합니다.
2. finally 블록이란?
2.1 개념
finally는 예외 처리(try-catch 블록)와 함께 사용되는 키워드입니다. finally 블록은 try 블록에서 예외가 발생하든 발생하지 않든, 항상 실행되는 코드 블록입니다.
✅특징:
- 예외 발생 여부와 관계없이 항상 실행됩니다.
- 주로 자원 해제(파일 닫기, 네트워크 연결 종료 등)에 사용됩니다.
- try 블록에서 return, break, continue 문이 실행되더라도 finally 블록은 실행됩니다.
2.2 finally 사용 예제
import java.io.*;
public class FinallyExample {
public static void main(String[] args) {
BufferedReader br = null;
try {
br = new BufferedReader(new FileReader("example.txt"));
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
System.err.println("IOException: " + e.getMessage());
} finally {
try {
if (br != null) {
br.close(); // 자원 해제
}
} catch (IOException e) {
System.err.println("Error closing BufferedReader: " + e.getMessage());
}
}
}
}
✅설명: try 블록에서 파일을 읽는 동안 IOException이 발생할 수 있습니다. finally 블록은 예외 발생 여부와 관계없이 항상 실행되어 BufferedReader를 닫아 자원을 해제합니다.
✅활용: 파일 I/O, 네트워크 연결, 데이터베이스 연결 등 외부 자원을 사용하는 경우, finally 블록을 사용하여 자원을 안전하게 해제하는 것이 중요합니다.
3. finalize() 메서드란?
3.1 개념
finalize()는 Java에서 Object 클래스에 정의된 메서드입니다. 가비지 컬렉터(Garbage Collector)가 객체를 메모리에서 제거하기 전에 자동으로 호출됩니다. (사용 권장 X)
✅특징:
- 객체가 가비지 컬렉션 대상이 될 때 한 번만 호출됩니다.
- 주로 자원 해제에 사용되지만, finally 블록에 비해 예측 가능성이 낮고 성능에 영향을 미치므로 사용이 권장되지 않습니다.
- finalize() 메서드의 실행 시점은 가비지 컬렉터에 의해 결정되므로, 정확한 실행 시점을 예측하기 어렵습니다.
✅주의사항:
- 사용하지 않는 것이 좋습니다. finalize() 메서드는 예측 불가능한 동작을 유발하고, 성능 저하를 초래할 수 있습니다.
- 자원 해제는 try-finally 블록을 사용하는 것이 훨씬 안전하고 효율적입니다.
- Java 9부터는 finalize() 메서드가 deprecated 되었습니다.
3.2 finalize() 사용 예제
class MyResource {
private FileDescriptor fd;
public MyResource(FileDescriptor fd) {
this.fd = fd;
}
@Override
protected void finalize() throws Throwable {
try {
// 자원 해제 (권장 X)
fd.sync();
// fd.close(); //deprecated
} finally {
super.finalize();
}
}
}
✅설명: MyResource 객체가 가비지 컬렉션 대상이 될 때 finalize() 메서드가 호출되어 FileDescriptor를 동기화합니다. 하지만 finalize() 메서드의 실행 시점을 예측하기 어렵고, 예외 처리에도 어려움이 있으므로 사용하지 않는 것이 좋습니다.
✅대안: AutoCloseable 인터페이스와 try-with-resources 구문을 사용하여 자원을 관리하는 것이 훨씬 안전하고 효율적입니다.
4. final vs finally vs finalize 비교
개념 | 설명 | 주요 역할 | 사용 위치 |
final | 변경 불가능 | 변수, 메서드, 클래스에 적용 | 변수, 메서드, 클래스 |
finally | 항상 실행되는 코드 블록 | 예외 처리 후 반드시 실행 | try-catch-finally 구문 |
finalize() | 가비지 컬렉션 전에 호출 | 객체 정리 작업 수행 | Object 클래스의 메서드 |
✅ final → 불변성을 보장하여 코드의 안정성과 예측 가능성을 높이는 데 사용됩니다.
✅ finally → 예외 발생 여부와 관계없이 항상 실행되는 블록으로, 자원 해제에 필수적입니다.
✅ finalize() → 객체 소멸 직전에 호출되는 메서드이지만, 예측 불가능한 동작과 성능 문제로 인해 사용이 권장되지 않습니다. (자바 9 이후 비권장)
5. 사용 시 주의사항
5.1 final 사용 시 주의할 점
- final 변수를 선언하면 한 번만 값을 할당할 수 있음
- final 메서드는 오버라이딩할 수 없음
- final 클래스는 상속할 수 없음
5.2 finally 사용 시 주의할 점
- finally 블록은 예외 발생 여부와 관계없이 반드시 실행됨
- System.exit(0); 호출 시 finally 블록이 실행되지 않을 수 있음
5.3 finalize() 사용 시 주의할 점
- finalize()는 가비지 컬렉터 실행 시 호출되지만, 즉시 실행이 보장되지 않음
- 자바 9부터 더 이상 사용을 권장하지 않음 (대신 try-with-resources 사용)
6. 정리
이번 글에서는 자바의 final / finally / finalize 개념을 비교하고 정리해 보았습니다.
📌 핵심 정리:
✅ final → 변경 불가능한 요소 지정 (변수, 메서드, 클래스)
✅ finally → 예외 처리 후 반드시 실행되는 블록
✅ finalize() → 객체가 제거되기 전에 호출 (비권장)
실제 개발에서 올바르게 사용하여 코드의 안정성을 높이는 데 활용해 보세요! 🚀
'이직&취업 > Java 기초 상식' 카테고리의 다른 글
자바에서 NullPointerException은 왜 발생하고 어떻게 해결하나요? (26) | 2025.04.06 |
---|---|
JAVA 직렬화(Serialization) 란 무엇인가? (14) | 2025.03.29 |
Wrapper 클래스와 Boxing & Unboxing (18) | 2025.03.27 |
추상 클래스(Abstract Class)와 인터페이스(Interface)를 알아보자!! (12) | 2025.03.27 |
오버라이딩(Overriding)과 오버로딩(Overloading) (19) | 2025.03.26 |