1. static이란?
- 클래스 로딩 시 메모리에 올라가는 클래스 레벨 멤버
- 객체 인스턴스 없이도 접근 가능
- 대표적인 사용처: 유틸리티 메소드, 공용 상수, 싱글톤 인스턴스
2. static 변수
- 모든 인스턴스가 공유함
- JVM의 Method Area(또는 Class 영역)에 저장됨
- 멀티스레드 환경에서는 동기화 주의
public class Example {
static int counter = 0;
public static void increment() {
counter++;
}
}
3. static 메소드
- 클래스명으로 직접 호출 가능 (
Example.increment())
- this 사용 불가
- 인스턴스 변수/메소드 직접 접근 불가
- static 변수에는 직접 접근 가능
public class Example {
static int value = 10;
public static void printValue() {
System.out.println(value);
}
}
4. static 메소드의 제약 사항
| 항목 | 설명 |
|---|
| 인스턴스 멤버 접근 | ❌ 불가 (this 없음) |
| 오버라이딩 | ❌ 불가 (메소드 숨김 발생) |
| 상태 공유 문제 | ⚠ 동기화 없이 접근 시 Race Condition 발생 가능 |
| 테스트 용이성 | ❌ 낮음 (DI/Mock 어려움) |
5. 메소드 숨김 (Method Hiding)
- static 메소드는 오버라이딩되지 않고 숨겨짐
- 호출은 참조 변수 타입 기준으로 결정됨
class Parent {
static void greet() { System.out.println("Parent"); }
}
class Child extends Parent {
static void greet() { System.out.println("Child"); }
}
Parent obj = new Child();
obj.greet();
6. static과 지역변수
- static 메소드 내에서도 지역 변수 사용 가능
- 지역 변수는 스택에 저장, static 여부와 무관하게 정상 동작
public static void example() {
int temp = 10;
}
7. Race Condition
- static 변수에 여러 스레드가 동시에 접근하면 발생
- 증상: 값이 덮어쓰기 되거나 불일치
- 해결 방법:
synchronized, Lock, AtomicInteger 등 사용
class Counter {
static int count = 0;
public static void increment() {
count++;
}
}
8. 사용 시 권장 사항
- 상태 없는 유틸 메소드에만 static 사용
- 상태를 갖거나 확장 가능성이 있는 경우 인스턴스 방식 권장
- 동기화, 테스트 용이성, 유지보수 관점에서 신중하게 사용
✅ 요약
| 구분 | 특징 |
|---|
| static 변수 | 클래스 로딩 시 공유, 모든 인스턴스에서 동일한 값 |
| static 메소드 | 객체 없이 호출 가능, 인스턴스 멤버 접근 불가 |
| 메소드 숨김 | 다형성 미지원, 참조 타입 기준 호출 |
| 지역 변수 | static 메소드 내에서도 사용 가능 (스택에 저장) |
| Race Condition | static 변수 접근 시 동기화 없으면 발생 |