📌 Static 이란?
스태틱(Static)은 고정이라는 뜻을 갖고 있습니다. Static 키워드를 사용하면 Static 변수와 Static 메서드를 만들 수 있는데 이 변수와 메서드는 메서드 영역에 올라가게 됩니다. 따라서 모든 곳에서 호출이 가능하고 이에 따라 속도도 빠르다는 특징을 갖고 있습니다. 하지만 Garbage Collector의 영역 밖에 존재하므로 Static을 자주 사용한다면 프로그램의 종료 시까지 메모리가 할당된 채로 존재하므로 메모리 누수가 발생된다는 단점이 있습니다.
만약 메모리 영역에 대해서 잘 모르신다면 밑의 글을 읽어보시는걸 추천드립니다.
🔎 Static 변수
예시로 게시물의 좋아요 기능을 구현해보겠습니다.
public class LikeCount {
int count;
public LikeCount(){
this.count++;
System.out.println("좋아요 개수 : " + count);
}
public static void main(String[] args) {
LikeCount one = new LikeCount();
LikeCount two = new LikeCount();
}
}
위의 예제를 보면 one, two 모두 새로운 객체가 생성될 때 서로 다른 메모리를 할당받게 됩니다.
좋아요 개수 : 1
좋아요 개수 : 1
그러나 static변수를 사용하면 두 객체가 생성될 때 one과 two객체는 하나의 메모리를 공유하게 됩니다. 또한 객체를 생성하지 않고 static 변수에 접근이 가능합니다.
public class LikeCount {
static int count;
public LikeCount(){
this.count++;
System.out.println("좋아요 개수 : " + count);
}
public static void main(String[] args) {
LikeCount one = new LikeCount();
LikeCount two = new LikeCount();
System.out.println(count);
}
}
좋아요 개수 : 1
좋아요 개수 : 2
2
🔎 Static 메서드
static 메서드도 마찬가지로 객체의 생성 없이 호출이 가능하고, 객체에서는 호출이 불가능하다. 또한 static 메서드 안에서는 인스턴스 변수 접근이 불가능합니다.
public class LikeCount {
// static int count;
int count;
public LikeCount(){
this.count++;
System.out.println("좋아요 개수 : " + count);
}
public static int getCount(){
return count; //컴파일 에러
}
public static void main(String[] args) {
LikeCount one = new LikeCount();
LikeCount two = new LikeCount();
System.out.println("총 좋아요 개수 : " + LikeCount.getCount());
}
}
위처럼 구현한 경우 count에서 컴파일 에러가 발생합니다.
public class LikeCount {
static int count;
// int count;
public LikeCount(){
this.count++;
System.out.println("좋아요 개수 : " + count);
}
public static int getCount(){
return count;
}
public static void main(String[] args) {
LikeCount one = new LikeCount();
LikeCount two = new LikeCount();
System.out.println("총 좋아요 개수 : " + LikeCount.getCount());
}
}
static 메서드 안에서는 static변수에 접근이 가능합니다. 그 이유는 밑에서 설명드리겠습니다.
📚 총정리
1. 인스턴스에 공통적으로 사용해야 하는 것에 static을 붙입니다.
- 인스턴스를 생성하면, 각 인스턴스들은 서로 다른 독립적인 메모리를 할당받기 때문에 서로 다른 값을 유지합니다.
- 경우에 따라 인스턴스들이 공통적인 값을 유지해야 하는 경우 static을 붙입니다.
2. static이 붙은 멤버변수는 인스턴스를 생성하지 않아도 사용 가능합니다.
- static이 붙은 클래스변수는 클래스가 메모리에 올라갈 때 자동적으로 생성되기 때문입니다.
3. static이 붙은 메서드에선 인스턴스 변수를 사용할 수 없습니다.
- 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문에 static이 붙은 메서드를 호출할 때 인스턴스가 생성되어 있을 수도 있고, 아닐 수도 있기 때문에 static이 붙은 메서드에서 인스턴스 변수의 사용을 허용하지 않습니다.
- 반대로, 인스턴스변수, 메서드에서는 static이 붙은 멤버들을 사용하는 것은 가능합니다.(인스턴스 변수가 존재한다는 것은 static 멤버들은 이미 메모리에 존재한다는 것을 의미)
4. 메서드 내에서 인스턴스 변수를 사용하지 않는다면, static을 붙이는 것을 고려합니다.
- static 메서드는 객체를 참조하지 않고 직접 클래스에 대해 호출됩니다. 이는 호출 체인이 단순해지므로 메서드 호출 시간이 줄어들 수 있습니다. 또한 컴파일러가 'static' 메서드에 대해 더 효율적인 최적화를 수행할 수 있기 때문에 실행 시간도 단축될 수 있습니다.
5. 클래스 설계 시 static의 사용지침
- 클래스의 멤버변수 중 모든 인스턴스에 공통된 값을 유지해야 하는 것이 있다면 static을 붙여줍니다.
- 작성한 메서드 중 인스턴스 변수를 사용하지 않는 메서드에 대해서 static을 붙일 것을 고려합니다.
❓스태틱을 사용하면 어떤 이점과 어떤 제약이 있을까요?
이점
- 메모리 측면에서 효율적일 수 있습니다. Static 메모리 영역에 저장되어 고정된 메모리 영역을 사용하기 때문에 매번 인스턴스를 생성하여 낭비되는 메모리를 줄일 수 있습니다.
- 객체를 생성하지 않고 사용하기 때문에 속도가 빠르다는 장점이 있습니다. 클래스가 메모리에 올라가는 시점에 바로 사용이 가능하기 때문에 속도면에서 이점이 있습니다.
단점
- 프로그램 종료 시까지 메모리에 할당된 채로 존재하기 때문에 가비지컬렉터의 영향을 받지 않아 메모리 누수가 발생할 수 있습니다.
- 객체지향적이지 못합니다. Static은 객체를 생성하지 않고 메모리의 Static 영역에 할당된 곳에서 여러 클래스들이 데이터를 불러옵니다. 이러한 특징은 객체의 데이터들이 캡슐화되어야 한다는 원칙을 위반합니다.
❓그럼 언제 사용하는 게 좋을까요?
사용하면 좋은 시기
- 유틸리티 함수 : 객체의 상태와 무관하게 동작하는 메서드
- 공유 자원 : 모든 인스턴스가 공유해야 하는 데이터 : 설정 값, 환경 변수등
- 싱글턴 패턴 : 객체를 단 하나만 존재하는 경우, 인스턴스를 static 변수로 관리하여 어디서든 접근 가능하게 할 수 있습니다.
❓컴파일 과정에서 static 동작 과정
- 로딩: JVM이 런타임에 .class 파일을 찾아 로드합니다.
- 링크: 로드된 클래스 파일을 검증하고, 필요한 바이너리 데이터를 준비하며, 메모리에서 사용할 준비를 합니다.
- 초기화: static 변수가 할당되고 static 초기화 블록이 실행됩니다.
JVM은 필요에 따라 클래스를 로드하므로, 전체 패키지에 있는 모든 클래스를 한 번에 로드하지는 않습니다. 대신, 필요할 때마다 개별 클래스를 로드하고 필요한 초기화를 수행합니다. 이는 메모리 사용을 효율적으로 관리하고, 필요하지 않은 클래스가 메모리를 차지하지 않도록 합니다.
'CS > Java' 카테고리의 다른 글
[Java] equals(), hashCode() (0) | 2024.05.05 |
---|---|
[Java] Error와 Exception (0) | 2024.05.02 |
[Java] 추상클래스와 인터페이스의 차이 (0) | 2024.04.19 |
[Java] 오버로딩(Overloading)과 오버라이딩(Overriding) 차이 (0) | 2024.04.14 |
[Java] 제네릭이란?(Generic) (0) | 2024.04.04 |