static 키워드는 자바에서 클래스 수준의 멤버를 선언할 때 사용합니다
static으로 선언된 멤버는 특정 객체(인스턴스)에 귀속되지 않고,
클래스 자체에 귀속되며 해당 클래스의 모든 인스턴스가 공유합니다
static 변수는 클래스에 1개만 존재하며, 클래스 로딩 시점에 생성되어 프로그램 종료 시 해제됩니다
모든 인스턴스가 같은 값을 공유"하며, 클래스명.변수명 형태로 접근하는 것이 관례입니다
또한 Garbage Collector의 관리 대상이 아닙니다
static 메소드는 객체 생성 없이 클래스명.메소드() 형태로 직접 호출할 수 있습니다
인스턴스 변수나 인스턴스 메소드에 직접 접근할 수 없으며, 오직 전달된 매개변수나 static 변수만 사용 가능합니다
static 초기화 블록은 클래스가 JVM에 의해 최초로 초기화(init)될 때 단 한 번 실행됩니다
static 변수들의 복잡한 초기화나 초기 설정을 수행할 때 사용됩니다
동일한 값이나 객체를 여러 인스턴스에서 공통으로 쓸 경우 static 변수로 선언하면
한 번만 메모리 할당을 받으므로 메모리 낭비를 줄일 수 있습니다
상수 값, 변하지 않는 설정, 자주 사용되는 문자열 리터럴 등을 static으로 선언하여
메모리 재사용성을 높이고 GC 부담을 줄일 수 있습니다
주 사용되는 유틸리티 메서드를 static으로 두면 객체 생성 없이 바로 호출 가능하여 불필요한 객체 생성 비용을 줄입니다
또한 복잡한 초기화가 필요한 자원을 static 초기화 블록에서 로딩해두면 매번 재생성할 필요 없이
반복 수행 비용을 절감할 수 있습니다.
static 멤버는 어디서든 클래스 이름만 알면 접근할 수 있기 때문에,
공통으로 사용되는 값이나 메서드를 전역처럼 제공할 수 있습니다
그렇기에 보통 유틸 클래스를 선언할때 자주 사용합니다
static 변수는 전역적으로 공유되므로,
여러 곳에서 값을 변경하면 프로그램 상태가 예측하기 어렵게 됩니다.
특히 상태를 관리하는 static 변수는 문제를 일으킬 수 있습니다
대표적으로 동시성 문제가 발생할 수 있습니다
하나의 static 변수를 여러 스레드가 동시에 수정하면 경합이 발생할 수 있습니다
static 자체는 스레드 세이프하지 않으므로, 멀티스레드 환경에서 공유 자원으로 동작할 경우
synchronized, 동시성 컬렉션(ConcurrentHashMap), Atomic 변수 등으로 보호해야 합니다
static으로 참조되는 객체는 클래스가 언로드되지 않는 한 Garbage Collection 대상이 되지 않습니다
따라서 대용량 데이터를 static에 보관하거나,
static 컬렉션에 데이터를 계속 추가하고 제거하지 않으면 메모리 누수(Memory Leak)로 이어져 OutOfMemoryError를 유발할 수 있습니다
static 메서드는 하위 클래스에서 오버라이드(override)가 불가능하며 (숨김(hide) 발생), static으로 설계된 부분은 향후 구조 변경이나 테스트 시 대체하기 어렵습니다.
static 초기화 블록이나 static 변수 초기화에서 시간이 많이 소요되는 작업을 수행하면,
해당 클래스 첫 사용 시점에 지연이 발생합니다
여러 JVM이나 분산 환경에서는 각각 별개의 static 데이터를 가집니다.
따라서 한 쪽에서 static 데이터를 변경해도 다른 프로세스에 반영되지 않아
데이터 일관성 문제가 발생할 수 있습니다
불변 상수(constant) 및 공용 설정 값에 대해 public static final 상수로 정의하여 전역적으로 편하게 활용할 수 있습니다
이렇게 한다면 메모리와 실행 시간을 절약하고 GC 부담을 줄일 수 있습니다
앞서 말했듯이 유틸 메소드로 활용할 수 있습니다
유틸 메소드는 객체 상태와 무관하기 떄문에 static 메서드로 제공하면,
불필요한 객체 생성을 방지하고 코드 가독성을 높일 수 있습니다
참고로 Java 8부터 인터페이스에도 static 메소드 구현이 가능해졌습니다
싱글톤(Singleton) 객체를 만들 때, 시스템 전역에서 하나만 존재해야 하는 객체를 만들 수 있습니다다
초기 로드 비용이 큰 자원을 static키워드로 캐싱하여 성능 튜닝에 기여할 수 있습니다
static 중첩 클래스 (static nested class) 방식으로 바깥 클래스의 인스턴스와 무관하게 사용되며,
바깥 객체에 대한 암묵적 참조가 없어 메모리 누수를 방지하는 데 도움을 줄 수 있습니다