< Static >
-> 클래스가 특별히 관리하는 변수
-> 클래스가 1개 이므로 변수도 하나만 존재한다. 반면에 인스턴스 변수는 클래스 안의 인스턴스의 수만큼 존재한다.
public class Data {
public String name;
public static int count; //static
}
예제 코드에서 name , count 는 둘다 멤버 변수이다.
멤버 변수(필드)는 static 이 붙은 것과 아닌 것에 따라 다음과 같이 분류할 수 있다.
- 멤버 변수(필드)의 종류
인스턴스 변수
: static 이 붙지 않은 멤버 변수, 예) name
- static 이 붙지 않은 멤버 변수는 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어 있다. 따라서 인스턴스 변수라 한다.
- 인스턴스 변수는 인스턴스를 만들 때 마다 새로 만들어진다.
클래스 변수
: static 이 붙은 멤버 변수, 예) count
- 클래스 변수, 정적 변수, static 변수 등으로 부른다. 용어를 모두 사용하니 주의하자
- static 이 붙은 멤버 변수는 인스턴스와 무관하게 클래스에 바로 접근해서 사용할 수 있고, 클래스 자체에 소속되어 있다. 따라서 클래스 변수라 한다.
- 클래스 변수는 자바 프로그램을 시작할 때 딱 1개가 만들어진다. 인스턴스와는 다르게 보통 여러곳에서 공유하는 목적으로 사용된다.
< 변수와 생명주기 >
- 지역 변수(매개변수 포함): 지역 변수는 스택 영역에 있는 스택 프레임 안에 보관된다. 메서드가 종료되면 스택 프레임도 제거 되는데 이때 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다. 따라서 지역 변수는 생존 주기가 짧다.
- 인스턴스 변수: 인스턴스에 있는 멤버 변수를 인스턴스 변수라 한다. 인스턴스 변수는 힙 영역을 사용한다. 힙 영역은 GC(가비지 컬렉션)가 발생하기 전까지는 생존하기 때문에 보통 지역 변수보다 생존 주기가 길다.
- 클래스 변수: 클래스 변수는 메서드 영역의 static 영역에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이다. 클래스 변수는 해당 클래스가 JVM에 로딩 되는 순간 생성된다. 그리고 JVM이 종료될 때 까지 생명주기가 어어진다. 따라서 가장 긴 생명주기를 가진다.
- 클래스가 JVM(Java Virtual Machine)에 로딩된다는 말은, 해당 클래스가 사용될 준비가 되었다는 것을 의미한다. 이 과정에서 클래스의 메타데이터(클래스 이름, 부모 클래스 정보, 메서드, 변수 등의 정보)가 메서드 영역에 배치된다.
- 그러나, 프로그램을 시작할 때 모든 클래스와 클래스 변수가 JVM에 한 번에 로딩되는 것은 아니다. 클래스는 필요할 때 동적으로 로딩된다. 즉, 클래스가 JVM에 로딩되는 시점은 다음과 같은 경우이다. - 해당 클래스의 인스턴스가 처음으로 생성될 때 / 해당 클래스의 static 멤버(변수나 메서드)에 처음 접근할 때 / Class.forName() 메서드를 통해 명시적으로 해당 클래스를 로딩할 때
- 클래스가 로딩되는 순간, 클래스 변수도 초기화되어 메서드 영역의 static 영역에 할당되고, JVM이 종료될 때까지 그 생명주기가 유지된다. 따라서 클래스 변수는 해당 클래스의 모든 인스턴스에 의해 공유되며, 클래스가 로드된 후부터 JVM이 종료될 때까지 계속 존재하게 된다.
static 이 정적이라는 이유는 바로 여기에 있다. 힙 영역에 생성되는 인스턴스 변수는 동적으로 생성되고, 제거된다.반면에 static 인 정적 변수는 거의 프로그램 실행 시점에 딱 만들어지고, 프로그램 종료 시점에 제거된다. 정적 변수는 이름 그대로 정적이다.
< 정적 변수 접근법 >
static 변수는 클래스를 통해 바로 접근할 수도 있고, 인스턴스를 통해서도 접근할 수 있다.
DataCountMain
package static1;
public class DataCountMain {
public static void main(String[] args) {
Data data1 = new Data("A");
Data data2 = new Data("B");
System.out.println("A count=" + data2.count);
System.out.println(Data.count);
}
}
- 인스턴스를 통한 접근
data2.count
정적 변수의 경우 인스턴스를 통한 접근은 추천하지 않는다. 왜냐하면 코드를 읽을 때 마치 인스턴스 변수에 접근하는 것 처럼 오해할 수 있기 때문이다.
- 클래스를 통한 접근
Data.count
정적 변수는 클래스에서 공용으로 관리하기 때문에 클래스를 통해서 접근하는 것이 더 명확하다. 따라서 정적 변수에 접근할 때는 클래스를 통해서 접근하자.