Java에서 static은 무엇을 의미하는가
Java의 static은 자주 쓰이지만, 정확히 설명하려고 하면 의외로 애매하게 남는 키워드다. 단순히 “객체 없이 접근할 수 있다”로만 이해하면, 왜 어떤 경우에는 적절하고 어떤 경우에는 위험한지 판단하기 어렵다.
핵심은 static이 인스턴스가 아니라 클래스에 속한 멤버를 만든다는 점이다.
static이 붙으면 무엇이 달라지나
일반 인스턴스 멤버는 객체마다 하나씩 존재한다. 반면 static 멤버는 클래스 기준으로 하나만 존재한다.
즉:
- 인스턴스 필드: 객체별 상태
static필드: 클래스 전체가 공유하는 상태
그래서 static은 단순한 문법 옵션이 아니라, 상태의 소속을 어디에 둘 것인지를 결정하는 선택이다.
1. static 변수
가장 익숙한 예는 클래스 변수다.
1
2
3
4
5
6
7
public class Counter {
static int count = 0;
public Counter() {
count++;
}
}
count는 Counter 인스턴스마다 따로 생기지 않는다. 모든 인스턴스가 같은 값을 공유한다.
이런 용도에 적합하다.
- 인스턴스 개수 카운트
- 공통 상수
- 애플리케이션 전역 설정값
하지만 공유 상태이기 때문에 무심코 쓰면 결합도가 올라가고, 멀티스레드 환경에서는 동시성 문제도 생긴다.
2. static 메서드
static 메서드는 객체 없이 클래스명으로 호출할 수 있다.
1
2
3
4
5
public class MathUtils {
public static int square(int x) {
return x * x;
}
}
1
int result = MathUtils.square(5);
이 방식이 자연스러운 이유는 메서드가 객체 상태를 필요로 하지 않기 때문이다.
즉, static 메서드는 보통:
- 입력만으로 결과를 계산하거나
- 클래스 수준의 공통 작업을 수행하거나
- 인스턴스와 무관한 유틸리티 역할을 할 때
적합하다.
왜 this를 쓸 수 없나
static 메서드는 특정 인스턴스에 속하지 않는다. 따라서 어떤 객체를 가리키는 this도 존재하지 않는다.
이 때문에 static 메서드 안에서는:
- 인스턴스 필드 직접 접근 불가
- 인스턴스 메서드 직접 호출 불가
하다.
결국 static 메서드는 “객체 상태를 모르는 문맥”이라고 이해하면 된다.
3. static 블록
static 블록은 클래스가 처음 로딩될 때 한 번 실행된다.
1
2
3
4
5
6
7
8
public class ConfigLoader {
static Map<String, String> config;
static {
config = new HashMap<>();
config.put("mode", "prod");
}
}
보통 이런 상황에서 사용한다.
- 복잡한 정적 초기화
- 클래스 로딩 시점의 준비 작업
다만 무거운 로직을 static 블록에 넣으면 클래스 로딩 비용이 커지고, 예외가 발생했을 때 원인 추적도 어려워질 수 있다.
4. static 중첩 클래스
중첩 클래스에 static을 붙이면 외부 인스턴스 없이 독립적으로 생성할 수 있다.
1
2
3
4
public class Outer {
static class Inner {
}
}
이 경우 Inner는 문법적으로 Outer 안에 있지만, 바깥 객체 인스턴스를 참조하지 않는다.
외부 상태가 필요 없는 보조 타입을 묶어둘 때 유용하다.
언제 static이 좋은 선택인가
다음 조건이면 대체로 자연스럽다.
- 인스턴스 상태를 읽지 않아야 한다
- 모든 객체가 같은 값을 공유해야 한다
- 클래스 수준에서 의미가 분명하다
예:
Math.maxCollections.emptyListLocalDate.now
이런 메서드들은 특정 객체 상태보다 클래스 수준의 공통 기능에 가깝다.
언제 남용이 되나
문제는 static이 편하다는 이유로 전역 상태처럼 쓰일 때다.
예를 들어:
- 어디서나 접근 가능한 mutable static 필드
- 테스트하기 어려운 전역 의존성
- 라이프사이클이 불분명한 캐시
이런 구조는 초기에는 간단해 보여도, 시간이 갈수록 코드 추적과 테스트가 어려워진다.
특히 static은 의존성 주입을 우회하기 쉽기 때문에, 설계상 책임을 흐리는 방향으로 자주 남용된다.
final과 같이 보는 게 중요하다
static final은 사실상 상수 선언에 가깝다.
1
public static final int MAX_RETRY = 3;
이 패턴은 문제없다. 오히려 가장 안전한 static 사용 방식 중 하나다.
반면 static인데 값이 계속 바뀌는 경우는 신중해야 한다. 공유 가변 상태는 항상 비용이 크다.
정리
Java에서 static은 “객체 없이 접근 가능”이라는 표면적 특징보다, 이 멤버가 인스턴스가 아니라 클래스에 속한다는 사실이 핵심이다.
static변수는 공유 상태를 만든다static메서드는 객체 상태를 모르는 문맥에서 실행된다static블록은 클래스 로딩 시점에 한 번 실행된다static중첩 클래스는 외부 인스턴스와 독립적이다
결국 판단 기준은 하나다.
이 동작이나 상태가 정말 객체마다 달라져야 하는가, 아니면 클래스 수준에서 하나면 충분한가
이 질문에 명확히 답할 수 있을 때 static은 단순하고 강력한 도구가 된다.
댓글
아직 댓글이 없습니다