Goal
- static 메모리 구조
- static 이란?
- static 을 사용하는 이유
- static 변수란?
- static 메소드란?
- static 블록이란?
참고
static 블록, static 메소드, static 변수 초기화 시점
[Class Loader] 클래스 로딩 시점 / 클래스 로딩 / 클래스 초기화
시작하기 전 ... 싱글턴을 생성하는 방법 중 Eager Initialization의 단점은 인스턴스를 미리 생성하기 때문에, 사용하지 않을 경우 메모리 점유로 인한 자원낭비가 된다였다. 여기서 나의 의문의 시작
dev-rosiepoise.tistory.com
static 메모리 구조
static 영역 | heap 영역 |
우리가 만든 클래스 | new 연산을 통해 생성한 객체 |
모든 객체가 공유하는 메모리로 gc의 대상이 아님 | gc의 대상이 되어 메모리 관리를 받는다 |
프로그램 종료시 까지 메모리가 할당된 채로 존재하기 때문에 자주 사용하면 퍼포먼스에 악영향을 끼친다 | gc로 인한 삭제 전까지 살아 있음 |
static 이란?
Java에서 static 키워드를 사용한다는 것은 어떠한 값이 메모리에 한번 할당되어 프로그램이 끝날 때 까지 그 메모리에 값이 유지된다는 것을 의미한다.
static을 사용하는 이유
인스턴스를 생성할 경우 각 인스턴스는 독립적이기 때문에 서로 다른 값을 유지한다. static을 사용하면 클래스가 메모리에 올라갈 때 이미 자동적으로 생성되기때문에 인스턴스들이 공통적으로 값을 유지해야할 때 사용한다.
static 변수
클래스 변수(static variable)는 클래스의 인스턴스와는 별개로 존재하는 변수.
즉, 클래스 변수는 객체를 생성하지 않고도 접근가능하며, 클래스 변수는 "static" 키워드를 사용하여 정의
1. static 을 사용하지 않은 경우
public class HeartCounter {
int count;
public HeartCounter(){
this.count++;
System.out.println("좋아요 개수 ="+count);
}
public static void main(String[] args){
HeartCounter hc1 = new HeartCounter();
HeartCounter hc2 = new HeartCounter();
}
}
결과
좋아요 개수 =1
좋아요 개수 =1
=> hc1, hc2 객체가 생성될 때 hc1의 count와 hc2의 count가 서로 다른 메모리를 할당 받게되기 때문에 위와 같은 결과가 나온다.
2. static 을 사용한 경우
public class HeartCounter {
static int count;
public HeartCounter(){
count++; // 더 이상 객체 변수가 아니므로, this삭제 권장
System.out.println("좋아요 개수 ="+count);
}
public static void main(String[] args){
HeartCounter hc1 = new HeartCounter();
HeartCounter hc2 = new HeartCounter();
}
}
결과
좋아요 개수 =1
좋아요 개수 =2
=> hc1, hc2 객체가 생성될 때 hc1, hc2는 하나의 메모리를 공유하기 때문에, 좋아요 개수가 2가 된다.
static 메소드
클래스의 인스턴스와는 별개로 존재하는 메서드로, 객체를 생성하지 않고도 호출할 수 있다. 클래스 메서드(static method)는 "static" 키워드를 사용하여 정의된다.
하지만 static 메소드는 클래스 변수만 사용할 수 있다는 단점이 있다. = 즉, static은 객체 생성없이도 사용이 가능하기 때문에 static메서드에는 인스턴스 변수를 사용할 수 없다. 인스턴스 변수는 인스턴스를 생성해야만 존재하기 때문이다.
public class HeartCounter {
static int count;
public HeartCounter(){
count++;
System.out.println("좋아요 개수 ="+count);
}
public static int getCount(){
return count;
}
public static void main(String[] args){
HeartCounter hc1 = new HeartCounter();
HeartCounter hc2 = new HeartCounter();
System.out.println("총 좋아요 개수= "+HeartCounter.getCount());
}
}
결과
좋아요 개수 =1
좋아요 개수 =2
총 좋아요 개수= 2
=> 객체 생성없이, 바로 접근가능 : HeartCounter.getCount()
참고
메서드에서 인스턴스변수를 필요로 한다면 static을 사용하지 않는 것이 좋고 인스턴스 변수가 필요하지 않으면 static을 붙이는 것이 좋다. 메서드 호출 시간이 짧아지기 때문에 효율이 올라간다.
static을 붙이지 않은 메서드는 실행할 때 메서드를 찾는 과정이 추가로 필요하기 때문에 시간이 더 걸린다.
1. util성 메소드 : 객체 생성 없이 바로 접근할 수 있어 static을 사용
public class MathUtils {
public static int add(int a, int b) {
return a + b;
}
public static int subtract(int a, int b) {
return a - b;
}
public static int multiply(int a, int b) {
return a * b;
}
public static int divide(int a, int b) {
return a / b;
}
}
2. 싱글톤 디자인 패턴
public class DatabaseConnection {
private DatabaseConnection() {}
private static DatabaseConnection instance = null;
public static DatabaseConnection getInstance() {
if (instance == null) {
instance = new DatabaseConnection();
}
return instance;
}
}
생성자를 private으로 선언하여 인스턴스화를 방지하고, getInstace() 메소드에서는 instance가 없는 경우 새로 생성하고, 그렇지 않은 경우에는 기존의 instacne를 리턴한다.
static 블록
객체가 생성되기 전에 한 번만 호출되고, 그 이후에는 호출하려고 해도 호출할 수 없다. 클래스 내에 선언되어 있어야하며, 메소드 내에서는 선언할 수 없다. 또한, static블록은 여러개를 선언할 수 있으며, 선언된 순서대로 차례로 호출되기 때문에 선언 순서는 매우 중요하다.
public class StaticBlock {
static int data=1;
public StaticBlock(){
System.out.println("StaticBlock 생성자");
}
static {
System.out.println("1. static 블록");
data=3;
}
static {
System.out.println("2. static 블록");
data=5;
}
public static int getData(){
return data;
}
}
public class StaticBlockCheck {
public static void main(String[] args){
StaticBlockCheck check = new StaticBlockCheck();
check.makeStaticBlockObject();
}
public void makeStaticBlockObject() {
System.out.println("creating block1");
StaticBlock block1 = new StaticBlock();
System.out.println("create block1");
System.out.println("------------------");
System.out.println("creating block2");
StaticBlock block2 = new StaticBlock();
System.out.println("create block2");
}
}
결과
creating block1
1. static 블록
2. static 블록
StaticBlock 생성자
create block1
------------------
creating block2
StaticBlock 생성자
create block2
=> 두개의 StaticBlock객체를 만들었지만, static 블록들은 단 한 번씩만 호출됨. 또한 생성자가 호출되기 전에 static 블록들이 호출 됨.
이 같은 static 블록은 클래스를 초기화할 때 꼭 수행되어야 하는 작업이 있는 경우 유용하게 사용됨.
static 초기화 블록이 잘못 사용되면?
static 블록은 해당 클래스가 로딩될 때 딱 한 번 호출되기 때문에, 정확한 실행 순서를 제대로 이해하지 않으면 원하는 동작이 수행되지 않거나 예상하지 못한 동작이 발생할 수 있다.
참고
자바의 신 by 이상민
'JAVA > about java' 카테고리의 다른 글
[Class Loader] 클래스 로딩 시점 / 클래스 로딩 / 클래스 초기화 (0) | 2023.07.02 |
---|---|
[Thread] 쓰레드 (0) | 2023.05.10 |
[Collection] Map (0) | 2023.05.01 |
[Collection] Set, Queue (0) | 2023.04.30 |
[Collection] List (0) | 2023.04.30 |