개발노트/Java

[Java Final] 키워드 파헤치기

superpil 2024. 5. 9. 13:05

개념

final은 변수, 메서드, 클래스의 값을 변경할 수 없게 만든다.

한마디로 낙장불입!

적절한 위치에 final을 사용하여 코드 작성 의도를 명확히 하고, 의도하지 않은 변화로부터 코드를 보호하는데 도움을 준다.

변수, 메서드, 클래스 중 어떤 곳에 사용하느냐에 따라 바꿀 수 없는 제약사항이 다르게 적용되기 때문에, 아래 내용을 통해 한번 자세히 알아보자!

 

변수(variable)에서 final

지역변수(local)

public static void main(String[] args) {
  // 지역변수
  final String superpil = "hello";
  superpil = "world"; // 컴파일 에러
}
  • superpil 변수를 선언하는 동시에 “hello”를 초기화했다.
  • 다음 "world"를 재할당하면 컴파일 에러가 발생!
  • 이유는 final 변수에 최초 한 번 값이 할당된 후 값을 변경했기 때문!

 

public static void main(String[] args) {
  // 지역변수
  final String superpil;
  superpil = "hello"; // 가능!
  superpil = "world"; // 컴파일 에러
}
  • 이번에는 superpil변수를 선언만 하고 초기화를 하지 않았다.
  • 이후 “hello”를 할당했다. 이건 정상 할당된다.
  • 이후 “world”를 재할당한다. 이건 컴파일 에러가 발생!
  • 여기서 중요한 것은 final은 최초로 초기화된 값을 변경하려 할 때만 에러가 발생한다는 점!

 

매개변수(parameter)

public static void main(String[] args) {
  demo("superpil");
}
  
public static void demo(final String param) {
  param = "hello"; // 컴파일 에러
  System.out.println(param);
}
  • 매개변수에도 final을 사용할 수 있다.
  • 매개변수로 받은 값을 변경 시 컴파일 에러 발생!
  • 매개변수 값을 메서드 내부에서 변경하지 못하도록 제한하고 싶을 때 사용하는 것이 좋다.

 

인스턴스 변수(instance)

public class Superpil {
  final int value = 20;
}
public static void main(String[] args) {
  Superpil superpil = new Superpil();
  System.out.println(superpil.value); // 20
  superpil.value = 50; // 컴파일 에러
}
  • Superpil클래스에 20으로 초기화된 value 변수가 있다.
  • Superpil클래스를 인스턴스로 생성하는 동시에 value는 20으로 설정된다.
  • 출력해 보면 당연히 20이 출력된다.
  • value값을 변경하게 되면 컴파일 에러 발생!
  • value에 final를 사용해 변경불가능하게 만들었기 때문!

 

// Superpil class
public class Superpil {
  final int value; // 컴파일 에러
}

// Main class
public static void main(String[] args) {
  Superpil superpil = new Superpil();
  superpil.value = 50;
}
  • 이번에는 final을 사용하고 바로 초기화하지 않아 보자.
  • 이전 지역변수 예제는 선언과 초기화를 분리해도 가능했다.
  • 인스턴스 변수도 지역변수처럼 가능할까? 정답은 No!

 

// Superpil class
public class Superpil {
  final int value1;
  final int value2;
  final int vlaue3 = 50;
  
  public Superpil(int value2){
   this.value1 = 20;
   this.value2 = value2;
  }
}

// Main class
public static void main(String[] args) {
  Superpil superpil = new Superpil(30);
  System.out.println(superpil.value1); // 20
  System.out.println(superpil.value2); // 30
  System.out.println(superpil.value3); // 50
}
  • final을 사용한 인스턴스 변수가 있다면 인스턴스가 초기화되는 시점에 변수는 반드시 초기화되어야 한다.
  • Superpil 클래스가 인스턴스로 생성될 때 value1, value2, value3은 생성자에 의해 초기화가 된다.
  • 당연히 value1, value2, value3의 값은 변경 불가능하다.

 

참조형

// superpil 클래스
public class Superpil {
  int value;
}

// main 클래스
public static void main(String[] args) {
	final Superpil superpil = new Superpil();
  superpil.value = 20;
  System.out.println(superpil.value); // 20
  
  superpil = new Superpil(); // 컴파일 에러
}
  • 이번에는 인스턴스 변수에 final을 사용하지 않고 superpil변수에 사용해 보자.
  • value값은 변경 가능하다. 하지만 superpi변수에 초기화된 값을 변경할 경우 에러가 발생한다.

 

참조형 변수 final 재할당

  • superpil 변수는 new Superpil 인스턴스의 참조값을 할당받았다.
  • 여기서 참조값이란, new Superpil의 (힙) 메모리 주소값이다.
  • 즉, 메모리 주소값이 할당된 것이고, value가 할당된 것이 아니기 때문에 값(value)은 변경 가능하다. (메모리 주소값으로 value를 찾아서 변경할 수 있다.)
  • 다만, final을 사용한 superpil 변수에 다른 값을 할당할 경우 참조값(메모리 주소값)이 변경되기 때문에 superpil변수는 변경 불가능하다.

 

메서드(method)에서 final

// 부모 클래스
public class Parent {

 public final void printMethod() {
  System.out.println("Parent");
 }
 
}

// 자식 클래스
public class Child extends Parent {
 
 // 컴파일 에러
 @Override
 public void printMethod() {}
 
}
  • 상속관계에서 일반적으로 자식은 부모의 메서드를 오버라이딩 할 수 있다.
  • 다만, 부모 메서드에 final을 사용하면 자식은 해당 메서드를 오버라이딩할 수 없다.
  • 부모 클래스에서 정의한 메서드를 변경하지 못하고 강제성을 의도하고 싶을 때 사용하면 좋다.

 

클래스(class)에서 final

// 부모 클래스
public final class Parent {}

// 자식 클래스
// 컴파일 에러
public class Child extends Parent {}
  • 메서드와 동일하게 final이 붙은 클래스는 다른 클래스가 상속 불가능하다.

 

정리

지금까지 작성된 내용을 요약해 보자.

  1. 지역변수: 한 번 초기화된 final 지역변수는 재할당할 수 없다.
  2. 매개변수: final 매개변수는 메서드 내에서 변경할 수 없어 값의 불변성을 보장한다.
  3. 인스턴스 변수: final 인스턴스 변수는 생성자에서 초기화되어야 하며, 초기화 이후에는 수정할 수 없다.
  4. 참조형 변수: 객체 참조 자체는 변경할 수 없으나, 객체 내부의 속성은 수정 가능하다.
  5. 메서드: final 메서드는 하위 클래스(자식)에서 오버라이드할 수 없다.
  6. 클래스: final 클래스는 상속될 수 없어, 클래스의 확장을 막는다.

 

주니어개발자의 성장기였습니다.

댓글로 부족한 내용이나 공유하고 싶은 의견을 채워주세요! 우리 함께 성장해요!😄