본문 바로가기

개발새발 개발자/Java

[Java] final 그게 뭔데, 어떻게 쓰는 건데

자바 API 문서를 뒤적거리다 final이란 키워드를 발견했습니다. 음 이게 뭐였지...? 하고 기억을 더듬어보니 상수 어쩌구 할 때 썼던거 같긴한데.....(흐릿흐릿)

final 그게 뭔데...어떻게 쓰는 건데...☆

final의 정의

위키피디아에 따르면 Java에서 사용하는 final은 다음과 같습니다.

자바 언어에서 final은 오직 한 번만 할당할 수 있는 entity를 정의할 때 사용된다. final로 선언된 변수가 할당되면 항상 같은 값을 가진다. 만약 final 변수가 객체를 참조하고 있다면, 그 객체의 상태가 바뀌어도 final 변수는 매번 동일한 내용을 참조한다.

즉, 한 번 값을 넣어두면 절대 바뀌지 않는 녀석입니다. 위의 인소 짤에서 남주가 외치는 영원 불멸의 사랑같은...☆ 영어로 final은 다들 알고 있듯 궁극적인, 최후의 등을 뜻하는데요, Java에서도 비슷한 의미를 담고 있는 것 같네요.

final은 클래스, 메서드, 변수 각각에 붙을 수 있습니다. 구체적인 내용을 살펴볼게요.

final 클래스

public final class MyFinalClass {...}    // final 클래스 선언

public class ThisIsWrong extends MyFinalClass {...} // 상속 불가!

final이 붙어있는 클래스는 상속할 수 없습니다. 이렇게 하면 보안이나 효율성 측면에서 장점이 있습니다. java.lang.System이나 java.lang.String처럼 자바에서 기본적으로 제공하는 라이브러리 클래스는 final을 사용한다고 하네요.

final 메서드

public class Base
{
    public       void m1() {...}
    public final void m2() {...}    // final 메서드 선언
}

public class Derived extends Base
{
    public void m1() {...}  // Base 클래스의 m1() 상속
    public void m2() {...}  // 오버라이딩, 즉 상속받은 메서드 수정 불가!
}

만약 어떤 클래스를 상속하는데 그 안에 final 메서드가 있다면, 오버라이딩으로 수정할 수 없습니다.

final 변수

public class Sphere {

    // PI 변수는 상수로 선언되어 수정할 수 없음
    public static final double PI = 3.141592653589793;

    public final double radius;
    public final double xPos;
    public final double yPos;
    public final double zPos;

    Sphere(double x, double y, double z, double r) {
         radius = r;
         xPos = x;
         yPos = y;
         zPos = z;
    }

    [...]
}

final 변수는 한 번 값을 할당하면 수정할 수 없습니다. 즉, 초기화는 한 번만 가능합니다.

public class Test {
  // 선언만 하고 초기화는 각 인스턴스에서 진행
  private final int value;

  public Test(int value) {
    this.value = value;
  }

  public int getValue() {
    return value;
  }
}

이렇게 먼저 선언해놓고 각각 다른 값을 갖도록 초기화 할 수도 있습니다. 물론 이렇게 한 번 값을 할당하면 다음부터는 수정할 수 없구요! 이런 형태를 blank final 변수라고 합니다.

final 변수의 짝꿍, static

final 변수에서 봤던 예제를 다시 한 번 보겠습니다.

public class Sphere {

    // PI 변수는 상수로 선언되어 수정할 수 없음
    public static final double PI = 3.141592653589793;

    public final double radius;
    public final double xPos;
    public final double yPos;
    public final double zPos;

    Sphere(double x, double y, double z, double r) {
         radius = r;
         xPos = x;
         yPos = y;
         zPos = z;
    }

    [...]
}

자, 자세히 보면 final 변수 앞에 static이 붙어있어요. 개발하다 보면 이렇게 static과 final이 붙어있는 모습을 많이 보셨을텐데요, 아무 생각 없이 관습적으로만 사용하다가 이유가 궁금해져서 찾아보았습니다.

static의 정의

일단, static의 정의부터 짚고 넘어가겠습니다. static은 변수나 함수에 붙는 키워드인데, 어디에 선언하는지에 따라 조금씩 다른 의미를 가집니다. 통용되는 일반적인 의미는 이렇습니다.

static을 붙이면 메모리에 딱 한 번만 할당되어 메모리를 효율적으로 사용할 수 있다.

메모리에 딱 한번만 할당한다는 건, 곧 같은 주소값을 공유한다는 거겠죠? 그래서 여기저기에 변수 하나로 공유할 수 있다는 장점이 있어요! 그러고 보니 final과 결이 유사하다는 생각이 드네요. 뭔가 고정되어 있는 느낌이 들죠?

static과 final의 궁합

final 변수를 쓰면 그 값을 계속 그대로 쓴다는 의미입니다. 어차피 같은 값 쓸 거, 계속 메모리 낭비할 거 없이 하나로 쭉 써도 되잖아요? 이렇게 static과 final을 같이 쓰면 효율성이 높아져서 자주 쓰인다고 하네요.

여기서 주의! 앞에서 배웠던 blank final 변수는 인스턴스마다 다른 값을 갖는다고 말씀드렸죠? 이렇게 final 이어도 초기화가 다르게 된다면 static을 사용하지 않게 됩니다.

각자 처한 상황에 따라 적절하게 사용하면 메모리를 잘 관리하며 개발할 수 있겠네요!

Reference
https://en.wikipedia.org/wiki/Final\_(Java)
https://en.wikipedia.org/wiki/Static\_(keyword)
https://djkeh.github.io/articles/Why-should-final-member-variables-be-conventionally-static-in-Java-kor/