Static 키워드는 주로 멤버 변수와 메서드에 사용된다.
멤버 변수에 static 키워드가 왜 필요한지 이해하기 위해 간단한 예제를 보다
인스턴스 내부 변수에 카운트 저장
Data1
package memory;
public class Data1 {
public String name;
public int count;
public Data1(String name) {
this.name = name;
count++;
}
}
생성된 객체의 수를 세고 싶다. 객체가 생성될 때마다 생성자를 통해 인스턴스의 멤버 변수인 count 값을 증가시킨다.
package memory;
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);
}
}
결과 값
A count:1
B count:1
C count:1
왜 count값이 1로 될까?
객체를 생성할 때마다 data1의 인스턴스는 새로 만들어진다. 그리고 그 인스턴스의 data1의 count 변수도 새로 만들어지기 때문이다.
인스턴스에서 사용되는 멤버 변수 count의 값은 인스턴스끼리 서로 공유하지 않는다. 이 문제를 해결할려면 변수를 서로 공유해야한다.
그럼 count 값을 별도 관리를 하는 Class을 새로 만들어본다.
package memory;
public class DataCountMain2 {
public static void main(String[] args) {
Counter s = new Counter();
Data2 ex1 = new Data2("a", s);
System.out.println("A count=" + s.count);
Data2 ex2 = new Data2("b", s);
System.out.println("b count=" + s.count);
}
}
package memory;
public class Data2 {
public String name;
//Counter의 count 가져오기
public Data2(String name, Counter s ){
this.name=name;
s.count++;
}
}
package memory;
public class Counter {
public int count;
}
A count=1
b count=2
Counter 인스턴스를 공용으로 생성하기 때문에 객체를 생성할 때마다 값을 정확하게 증가 시킬 수 있다.
1. Data2("A") 인스턴스를 생성하게 되면 생성자를 통해 Counter 인스턴스에 있는 count 값을하나 증가 시킨다.
이때 count 는 값이 1이 된다.
2. Data2("b") 의 인스턴스를 생성하면 생성자를 통해 Counter 인스턴스에 있는 count 값을 하나 증가 시킨다.
3. 동일하게 "c" 도 그렇게 된다.
최종적으로
그러나 계속 밖에서 만드는 것이 귀찮아진다.
외부의 도움을 받지 않고 공용의 변수를 받아서 할 수 없을까?
Static 변수
특정 클래스에 공용으로 함께 사용할 수 잇는 변수를 만들 수 있다면, 편리할 것이다.
Static 키워드를 사용하면 고용으로 함께 사용하는 변수를 만들 수 있다.
package memory;
public class Data3 {
public String name;
public static int count; //static 추가
//생성자 생성
public Data3(String name) {
this.name = name;
count++;
}
}
위의 구조에서 static 만 추가하여 생성하였다.
package memory;
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);
Data3 data4 = new Data3("d");
System.out.println("d count" + Data3.count);
}
}
결과 값:
a count1
b count2
c count3
d count4
왜 Static 은 같이 처리가 되는 걸까?
static이 붙은 멤버 변수는 메서드 영역에서 관리한다.
따라서 static이 붙은 count 는 인스턴스 영역에 생성되지 않는다. 이는 heap영역에 생성되지 않는 것을 의미한다.
생성자에는 count++ 코드가 있다. count 는 static이 붙은 정적 변수다. 정적 변수는 인스턴스 영역이 아니라 메서드 영역에서 괸리한다.
따라서 메서드 영역에 있는 count 의 값이 하나 증가한다.
Static 변수는 쉽게 이야기해서 클래스인 붕어빵 특별하게 관리하는 변수이다. 붕어빵 틀은 1개이므로 클래스변수도 하나만 존재한다.
반면에 인스턴스인 붕어빵은 인스턴스 수만큼 변수가 존재한다.
정리
멤버 변수(필드)의 종류
1. 인스턴스 변수 : static 가 붙지 않은 변수, static이 붙지 않은 멤버 변수는 인스턴스를 생성해야 사용할 수 있고, 인스턴스에 소속되어있다. 힙 영역에서 사용되며, 힙 영역은 가비지 컬렉션이 발생하기 전까지는 생존하기 때문에 보통 지역변수보다 생존 주기가 길다.
Public class Data3 {
public String name;
2. 클래스 변수: static이 붙은 멤버 변수 이는 클래스변수 정적변수 static 변수라고 부른다. 이는 메서드 영역의 static에 보관되는 변수이다. 메서드 영역은 프로그램 전체에서 사용하는 공용 공간이며, jvm에 로딩 되는 순간에 생성된다. 그리고 jvm이 종료될때까지 이어지기 때문에 가장 긴 생명주기를 가진다.
예) count
Public class Data3 {
public static int count;
3. 지역 변수: 지역 변수는 스택 영역에 있는 스택 프레임안에 보관된다. 메서드가 종료되면 스택 프레임도 제거되는데, 이때 해당 스택 프레임에 포함된 지역변수도 함께 제거된다. 따라서 지역 변수는 생존 주기가 짧다.
왜 Static, 정적이라고 불리는 걸까?
힙 영역에는 정적으로 생성되는 변수가 추가된다. 인스턴스 변수는 동적으로 생성되며, 제거된다.
반면에 static인 정적 변수는 거의 프로그램 실행 시점에 만들어지며, 종료 시점에서 제거가 되기 때문에 정적이라고 한다.
'JAVA' 카테고리의 다른 글
[Java] 상속 (1) | 2024.10.30 |
---|---|
[Java] Static 메서드1 (1) | 2024.10.27 |
[Java] 메모리구조 (1) | 2024.10.27 |
[Java] 캡슐화 (1) | 2024.10.27 |
[Java] 생성자 (0) | 2024.10.23 |