❗해당 포스팅은 인프런에서 제공해 주는 강의 내용을 개인적으로 정리하였음을 알려드립니다.
지난번 자바 메모리 구조에서 스택영역에는 메서드 및 지역변수가, 힙영역에는 객체(인스턴스)가 관리된다는 것을 확인했다. 그렇다면 메서드 영역에서는 어떤 변수가 관리될까? 이를 이해하기 위해 우선 static 변수를 이해해야 한다.
static 변수는 왜 필요할까..?
다음 예시를 확인해 보자
package static1;
public class Data1 {
public String name;
public int count;
public Data1(String name) {
this.name = name;
count++;
}
}
생성된 객체의 수를 세기 위해 count 값을 증가시킨다면 결과는 어떻게 나올까?
package static1;
public class DataCountMain1 {
public static void main(String[] args) {
Data1 data1 = new Data1("A");
System.out.println("A count=" + data1.count);
Data1 data2 = new Data1("B");
System.out.println("B count=" + data2.count);
Data1 data3 = new Data1("C");
System.out.println("C count=" + data3.count);
}
}
Data1 인스턴스는 객체를 생성할 때마다 새로 만들어지고, count 변수도 새로 만들어지기 때문에 data1, data2, data3 결괏값이 모두 1이 나온다.
이 문제를 해결하기 위해서는 변수를 공유해야 한다.
count를 사용할 공유 객체를 하나 만든다.
package static1;
public class Counter {
public int count;
}
package static1;
public class Data2 {
public String name;
public Data2(String name, Counter counter) {
this.name = name;
counter.count++;
}
}
package static1;
public class DataCountMain2 {
public static void main(String[] args) {
Counter counter = new Counter();
Data2 data1 = new Data2("A", counter);
System.out.println("A count=" + counter.count);
Data2 data2 = new Data2("B", counter);
System.out.println("B count=" + counter.count);
Data2 data3 = new Data2("C", counter);
System.out.println("C count=" + counter.count);
}
}
하나의 Counter 객체를 사용하고 공유하기 때문에 값이 증가한다.
이렇게 원하는 결과를 얻었지만 Data2 객체와 관련된 일인데 Counter 클래스를 별도로 생성해야 하는 번거로움이 있다.
이제 static 키워드를 사용해 보자
package static1;
public class Data3 {
public String name;
public static int count;
public Data3(String name) {
this.name = name;
count++;
}
}
멤버 변수 앞에 static을 붙이면 static 변수 또는 정적 변수 또는 클래스 변수라 한다.
package static1;
public class DataCountMain3 {
public static void main(String[] args) {
Data3 data1 = new Data3("A");
System.out.println("A count = " + Data3.count);
Data3 data2 = new Data3("B");
System.out.println("B count = " + Data3.count);
Data3 data3 = new Data3("C");
System.out.println("C count = " + Data3.count);
}
}
static이 붙은 멤버 변수는 메서드 영역에서 관리되는데 이 변수에 접근하려면 클래스명.변수명으로 접근한다. 같은 클래스에 있는 정적 변수라면 클래스명을 생략할 수 있다.
이렇듯 static 변수를 사용하면 공용변수를 사용하게 되므로 문제 해결이 가능하다.
static 변수는 붕어빵 틀 = 1개
인스턴스 변수는 붕어빵 = 여러 개
멤버 변수의 구분
인스턴스 변수 : static이 붙지 않은 변수
클래스 변수 : static이 붙은 멤버 변수 (정적 변수, static 변수 등으로 불림)
static이 붙으면 인스턴스와 무관하게 클래스에 바로 접근 가능
생명주기
지역 변수(매개변수 포함) : 스택 프레임 안에 보관. 스택 프레임이 제거되면 해당 스택 프레임에 포함된 지역 변수도 함께 제거된다.
인스턴스 변수 : 인스턴스에 있는 멤버 변수, 힙영역 사용, 힙영역은 gc가 발생하기 전까지 생존함. 지역 변수보다 생존 주기가 길다.
클래스 변수 : 메서드 영역의 static 영역에 보관. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간!! 클래스변수는 JVM에 로딩될 때부터 종료될 때까지 생명주기가 이어지므로 생명주기가 가장 길다.
//인스턴스를 통한 접근
Data3 data4 = new Data3("D");
System.out.println(data4.count);
//클래스를 통한 접근
System.out.println(Data3.count);
static 변수는 인스턴스를 통한 접근도 가능하고, 클래스를 통한 접근도 가능하지만 인스턴스를 통한 접근을 추천하지 않는다. 코드를 가져다 쓰는 사람 입장에서 해당 변수를 인스턴스 변수로 오해할 수 있음
'Back-end > Java' 카테고리의 다른 글
[Java] final 변수와 상수 (3) | 2024.12.20 |
---|---|
[Java] static 메서드 (1) | 2024.12.20 |
[Java] 자바 메모리 구조 (0) | 2024.12.14 |
[Java] 기본형과 참조형 (3) | 2024.12.03 |
[Java] 배열의 도입 (2) | 2024.11.27 |