Static은 클래스 레벨의 멤버를 정의하는 키워드입니다.
static으로 선언된 변수/메서드는 객체 생성 없이 클래스명.멤버명으로 접근할 수 있고,
해당 클래스의 모든 인스턴스가 공유합니다.
메모리 관점에서 보면,
클래스가 로딩되면 클래스 메타데이터가 Method Area(HotSpot 기준 Metaspace) 에 적재되고,
static 멤버는 JVM이 클래스 단위로 관리합니다.
static 멤버의 수명은 보통 프로그램 종료까지로 이해해도 되지만,
정확히는 해당 클래스를 로딩한 ClassLoader의 수명에 종속됩니다.
(WAS/DevTools 환경에서는 ClassLoader 교체로 함께 정리될 수 있음)
1. Static의 특징
Static의 주요 특징은 다음과 같습니다.
public class Company {
static String companyName = "Tech Corp"; // 모든 인스턴스가 공유
String employeeName; // 인스턴스별로 다름
static void printCompany() {
System.out.println(companyName); // OK
// System.out.println(employeeName); // 컴파일 에러 (인스턴스 멤버 접근 불가)
}
}
// 사용
Company.companyName; // 객체 생성 없이 접근
Company.printCompany(); // 객체 생성 없이 호출
Company emp1 = new Company();
Company emp2 = new Company();
// emp1과 emp2는 같은 companyName을 공유
- 클래스 레벨 소속: static 멤버는 객체가 아니라 클래스에 속합니다.
- 공유: 모든 인스턴스가 같은 static 값을 공유합니다.
- 객체 생성 불필요: 클래스명.멤버명으로 바로 접근 가능합니다.
- 제약사항: static 메서드는 인스턴스 멤버를 직접 사용할 수 없습니다. (this가 없음)
2. 메모리 관점에서의 Static
메모리 구조는 보통 이렇게 설명합니다.
[Method Area (HotSpot: Metaspace)]
- 클래스 메타데이터(클래스 구조, 메서드/필드 정보 등)
- 메서드 바이트코드/런타임 상수풀 등
→ JVM이 클래스 단위로 관리
[Heap]
- new로 생성된 객체(인스턴스)
- (구현체에 따라) 클래스 런타임 데이터/정적 필드 값이 힙에 존재하기도 함
→ GC 관리 대상
[Stack]
- 지역 변수, 매개변수, 호출 프레임
→ 스레드별 독립
여기서 static 멤버는
클래스 로딩 시 JVM이 클래스 단위로 준비하고 관리하며,
인스턴스 멤버는 new로 생성된 객체가 Heap에 만들어질 때 함께 생성됩니다.
3. Static, 실무 활용 사례
유틸리티 클래스, 상수 정의 시에 사용합니다.
4. Static의 장단점
장점
- 공통 데이터 공유: 클래스 전체에서 같은 값/자원을 공유 가능
- 편리한 접근: 객체 생성 없이 바로 사용 가능
- 유틸/상수 표현에 적합: 의미적으로 클래스 소속임을 명확히 함
단점
- 멀티스레드 이슈: 공유 상태(static mutable)는 동기화 필요
- 테스트 어려움: 상태가 남아 테스트 독립성을 해칠 수 있음
- 결합도 증가: 남용하면 전역 상태처럼 되어 설계가 나빠질 수 있음
- 메모리/수명: ClassLoader 수명까지 유지될 수 있어(특히 WAS) 잘못 참조하면 누수 원인이 될 수 있음
5. 자주 하는 질문
Q1: Static 변수는 언제 초기화되나요?
A: 클래스가 처음 능동적으로 사용될 때 JVM이 클래스 초기화(initialization) 를 수행하며,
이때 static 필드 초기화와 static 블록이 딱 한 번 실행됩니다.
public class InitOrder {
static int a = 10;
static int b;
static {
b = 20;
System.out.println("클래스 초기화");
}
}
Q2: Static import는 무엇인가요?
A: static 멤버를 클래스명 없이 사용할 수 있게 하는 문법입니다.
Q3: Static 변수의 동기화는 어떻게 하나요?
A: synchronized 또는 Atomic 같은 동시성 도구를 사용합니다.
import java.util.concurrent.atomic.AtomicInteger;
public class SafeCounter {
private static int count = 0;
private static final AtomicInteger atomicCount = new AtomicInteger(0);
public static synchronized void increment() {
count++;
}
public static void increment2() {
synchronized (SafeCounter.class) {
count++;
}
}
public static void increment3() {
atomicCount.incrementAndGet();
}
}
'자바 JAVA' 카테고리의 다른 글
| Logger를 private static final로 선언하는 이유 3가지 (0) | 2026.01.08 |
|---|---|
| [Network] Apachi, Nginx, Tomcat 이 하는일이 뭘까? (Apachi와 NginX의 차이점) (1) | 2022.12.11 |
| [Mac] JAVA 11(Zulu JDK11) 다운로드 및 설치 (0) | 2022.12.08 |
| [java] HashMap 순회, 4가지 반복문 (2) | 2022.12.07 |
| [java] 자바 메모리 구조(static, stack, heap) (0) | 2022.11.18 |
댓글