Static 멤버와 Non-Static 멤버
자바 클래스 멤버는 static 키워드의 유무에 따라 객체 멤버(Non-Static)와 클래스 멤버(Static)로 구분되며, 이는 메모리 관리 및 접근 방식에서 근본적인 차이를 발생시킨다.
객체 멤버(Non-Static)
static 키워드가 없는 멤버는 객체에 종속되며, 객체마다 독립적인 생명 주기를 가진다.
-
메모리 위치 및 할당 시점: 힙 영역에 할당되며, 클래스로부터 객체를 new 키워드로 생성할 때마다 메모리에 새롭게 할당된다.
-
접근 방식: 객체 참조 변수를 통해서만 접근할 수 있다.
class Car {
public int speed = 0;
}
public class CarFactory {
public static void main(String[] args) {
Car myCar = new Car();
myCar.speed = 10;
}
}
- 공유 범위: 객체 간에 공유되지 않으며, 각 객체는 자신만의 고유한 값을 저장한다.
클래스 멤버(Static)
static 키워드가 붙은 멤버는 클래스 자체에 소속되며, 단 하나의 복사본만 존재하고 모든 객체가 이를 공유한다.
-
메모리 위치 및 할당 시점: 메소드 영역 또는 정적 영역에 할당되며, 프로그램이 시작되고 클래스가 JVM에 로드될 때 할당된다. 이는 객체 생성 시점보다 빠르며, 객체 생성 여부와는 무관하다.
-
접근 방식: 객체의 생성 없이 클래스 이름을 통해 바로 접근하는 것이 권장된다.
-
공유 범위: 해당 클래스의 모든 객체가 이 값을 공유한다. 한 객체가 값을 변경하면, 다른 모든 객체에서 즉시 변경된 값을 보게 된다.
-
용도: 모든 객체에 공통적으로 적용되는 상수, 객체의 개수를 세는 카운터, 객체에 종속되지 않는 유틸리티성 메소드 등에 사용된다.
객체 멤버 vs 클래스 멤버 비교표
자바의 클래스 멤버와 객체 멤버의 특징을 한 눈에 비교할 수 있도록 정리한 표는 다음과 같다.
| 구분 | 객체 멤버(Non-Static) | 클래스 멤버(Static) |
|---|---|---|
| 키워드 | 없다. | static |
| 메모리 위치 | 힙 영역 | 메소드 영역 |
| 메모리 할당 시점 | 객체가 생성될 때마다 할당된다. | (프로그램 시작 시)클래스가 JVM에 로드될 때 할당된다. |
| 존재 개수 | 객체 수 만큼 각각 존재한다. | 클래스 당 단 하나만 존재한다. |
| 접근 방법 | 객체 참조 변수를 통해서만 접근이 가능하다. | 클래스 이름을 통해 접근이 권장된다. |
| 공유 여부 | 각 객체마다 고유한 값을 가진다. | 해당 클래스의 모든 객체가 값을 공유한다. |
| 호출 제약 | Static 멤버는 Non-Static 멤버에 직접 접근이 가능하며, Non-Static 멤버를 사용하려면 객체를 생성해야 한다. | Non-Static 멤버는 Static 멤버에 제약 없이 직접 접근이 가능하다. |
main() 메소드가 static 키워드로 선언되어야 하는 이유
자바의 main() 메소드 선언부에 포함된 static 키워드는 가능성이 아니라 프로그램의 안정적인 실행을 위한 필수적인 제약 조건이다.
-
실행 진입점(Entry Point) 확보: JVM은 프로그램을 실행할 때, 특정 클래스의 시그니처를 가진 메소드를 가장 먼저 찾아 호출하도록 설계되어 있다. 만약 main() 메소드가 static 키워드로 선언되지 않고 객체 멤버라면, JVM은 main() 메소드를 호출하기 위해 해당 클래스의 객체를 먼저 생성해야만 하고 이는 클래스의 로딩, 실행 등 복잡한 초기화 과정을 필요로 한다. 따라서 static 키워드로 선언함으로써, 객체의 생성 과정 없이 클래스가 메모리에 로드되는 순간 JVM이 클래스 이름을 통해 즉시 main() 메소드를 호출하여 프로그램을 실행할 수 있게 하는 것이다.
-
일관된 실행 환경 제공: static 멤버는 JVM 내에서 오직 하나만 존재하며, 모든 환경에서 동일한 상태와 접근 경로를 보장한다. 이는 JVM이 운영체제나 실행 환경에 관계없이 일관되고 예측 가능한 방법으로 프로그램을 실행할 수 있도록 하는 메커니즘이다.
-
main() 메소드 내 접근 제약: main () 메소드가 static 키워드로 선언되었기에, 메소드 내부에서는 동일 클래스 내의 Non-Static 멤버에 직접 접근할 수 없다.
-
이유: Non-Static 멤버는 객체가 생성될 때 힙 영역에 존재하게 되는데, main() 메소드가 실행되는 시점에서는 아직 객체가 생성되지 않았기 때문이다.
-
해결: main() 메소드 내에서 인스턴스 멤버를 사용하려면, 반드시 해당 클래스의 객체를 명시적으로 생성한 후 객체 참조를 통해 접근해야 한다.
-