[Java]static 과 final

Jongmyung Choi·2022년 5월 25일
4
post-thumbnail

싱글톤 패턴을 공부하면서 객체를 static 영역에 딱 1개만 생성할때 private static final 을 사용하는 것 을 보고 항상 헷갈렸던 static 과 static final에 대해 확실히 정리하려고 글을 작성하게 됐다.


Static 이란?

static은 컴파일러에 의해 .java에서 .class 파일로 로드될 시 우선적으로 jvm 의 static 메모리에 할당된다.

static(정적) 멤버는 객체(인스턴스)에 소속된 것이 아니라 클래스에 소속 된 것 이다. 클래스 로더가 클래스(바이트 코드)를 로딩해서 메소드 메모리 영역에 적재할 때 클래스별로 관리된다.

→ 클래스의 로딩이 끝나면 별도의 인스턴스 생성 필요없이 바로 사용할 수 있다.

Static 은 언제 사용할까?

  1. static 변수와 static 메소드는 동일한 타입의 객체들이 서로 자원을 공유할 경우에 많이 사용된다.
  2. 객체 생성 없이 사용할 수 있는 필드와 메소드를 생성하고자 할 때 활용한다.
  3. static 으로 선언된 것들은 프로그램 종료시 까지 유지된다.
  4. static 객체에서 static 이 아닌 객체를 호출하는것은 불가능합니다.
    → static 이 먼저 정의되기 때문에 정의되지 않은 객체를 호출 할 수 없다.

Final 이란?

Final : 최종적인, 결코 수정할 수 없음
final은 해당 entity가 오로지 한 번 할당될 수 있음을 의미합니다.

final 변수
해당 변수가 생성자나 대입연산자를 통해 한 번만 초기화 가능함을 의미합니다. 상수를 만들 때 응용합니다.
final 메소드
해당 메소드를 오버라이드하거나 숨길 수 없음을 의미합니다.
final 클래스
해당 클래스는 상속할 수 없음을 의미합니다. 문자 그대로 상속 계층 구조에서 ‘마지막’ 클래스입니다.
보안과 효율성을 얻기 위해 자바 표준 라이브러리 클래스에서 사용할 수 있는데, 대표적으로 java.lang.System, java.lang.String 등이 있습니다.

Final != 상수
Final 은 각 인스턴스마다 다른 값을 가질 수 있다.
Final != const
const는 선언 시 값을 지정해야한다.
final은 선언 시 값을 지정하거나, 나중에 생성자 혹은 setter로 지정 가능하다.

Static final?

클래스 내부 또는 외부에서 참조의 용도로만 선언된 변수는 static final로 선언한다.
→ 선언과 동시에 값을 지정하여야하며 그 이후에는 수정이 불가하다.

여러 궁금증들의 해결

static final vs final static

→ 둘다 결과적으로 차이가 없다. 관례적으로 static final을 사용한다.

static 없는 final , final 없는 static

static 없는 final
각 인스턴스마다 서로다른 final 멤버 변수를 생성자를 통해서 초기화 시키는 경우에는 static 을 사용하지 않는다. 즉 인스턴스 생성시 한번만 초기화 하고 쭉 변화 없이 사용할 내용이라면 아주 잘 어울린다.
Spring 에서 DI(Dependency Injection) 기법을 사용해 클래스 내부에 외부 클래스 의존성을 집어넣는 경우가 그것이다.

public class MyController {
  private final MyService myService;

  @Autowired
  public MyController(MyService myService) {
    this.myService = myService;
  }
}

만약 static final 로 한다면 선언과 동시에 초기화를 해야하기 때문에 외부의 의존성을 받을 수 없다.

final 없는 static
→ 기술적으로는 가능하지만 좋은 코딩 관례는 아니다. static은 클래스 범위의 전역변수라고 볼 수 있는데 final 없이 사용하면 얼마든지 값이 바뀔 수 있기 때문에 이를 mutable 하다고 한다.
모든 클래스 인스턴스에서 접근하여 그 값을 변경할 수 있음을 의미하므로, 값을 추론하거나 테스트하기 어렵게 만들고 동시성 프로그래밍을 어렵게 만드는 요인이 된다.

public static void main(String[] args)

Static : 메인 메소드는 객체를 따로 생성하지 않고 무조건 호출되어야 하므로 static을 사용한다.
Public : 자바는 클래스 기반 언어이고, JVM에서 엔트리포인트인 메인 메서드에 어느 곳에서든 자유롭게 접근하기 위해 public이 되어야 한다.
Void : main이 프로그램의 시작과 끝인데 어떠한 값을 반환 한다는 것이 의미가 없고 반환을 하면 안되기 때문에 void 를 사용한다.

🗣 (번외) 파라미터 String[] args 는 난 필요 없는데 안쓰면 안돼?
→ Java의 경우 API 에서는 public static void main (String[] args)단 한개만 엔트리포인트로 정의했기 때문에 무조건 써야된다.
역사적으로 java 확장자 파일을 class 파일로 직접 컴파일을 시키던 시절에 main 에 특정 파라미터를 전달하고 싶을때 사용 했었다.

💡 엔트리포인트 : 프로그램의 시작이 되는 시작점

public static final과 private static final

public static final
public 접근 제한자에 의해서 외부에서도 해당 오브젝트에 접근하여 값을 활용할 수 있다.
private static final을 선언한 변수를 사용하면 재할당하지 못하며, 메모리에 한 번 올라가면 같은 값을 클래스 내부의 전체 필드, 메서드에서 공유한다.
→ 상수로 사용한다.

private static final
private 접근 제한자에 의해서 외부에서는 접근이 불가능하고, 해당 클래스 내부에서만 값을 활용할 수 있다.

참고

https://velog.io/@taehee-kim-dev/static-final-static-final
https://gobae.tistory.com/3
https://djkeh.github.io/articles/Why-should-final-member-variables-be-conventionally-static-in-Java-kor/

profile
총명한 개발자

0개의 댓글