static 변수
- 클래스의 인스턴스를 생성하지 않아도 접근 가능
- 모든 객체가 static 변수를 공유
static 메서드
- 클래스의 인스턴스를 생성하지 않아도 호출 가능
static 블록
- 클래스가 메모리에 로드될 때 단 한 번만 실행
class MyClass {
static {
System.out.println("클래스가 로드될 때 한 번만 실행됩니다.");
}
}
public class Main {
public static void main(String[] args) {
new MyClass(); // MyClass가 메모리에 로드될 때 static 블록 실행
new MyClass(); // static 블록 실행 안 함
new MyClass(); // static 블록 실행 안 함
}
}
☝️ 위 코드에서 MyClass 객체를 여러 번 생성해도, 문장은 처음 객체를 생성했을 때만 출력된다.
프로그램을 종료하게 되면 JVM이 메모리를 비우고, 재실행될 때 JVM이 다시 메모리에 클래스를 로드하기 때문에 static 블록은 다시 실행하게 된다.
static 클래스
- 클래스 안에 선언된 클래스(=내부 클래스)만 static 클래스로 지정이 가능하다.
- 외부 클래스의 인스턴스를 생성하지 않아도 바로 내부 클래스를 사용할 수 있다.
class Outer {
static class Inner {
void display() {
System.out.println("Static 내부 클래스입니다!");
}
}
}
public class Main {
public static void main(String[] args) {
Outer.Inner obj = new Outer.Inner(); // 바깥 클래스 없이 바로 사용 가능!
obj.display();
}
}
☝️ 내부 클래스가 static 클래스가 아니었다면, 내부 클래스를 사용할 때 `new Outer().new Inner();` 와 같은 코드를 작성해야 한다.
// Map.Entry가 대표 예시인데 이해 안 됨! -> Map 공부하고 다시 보기
일반 내부 클래스 vs 정적 내부 클래스
내부 클래스 유형 | 바깥 클래스 속성 접근 가능 여부 |
일반 내부 클래스 (static 없음) | ✅ 바깥 클래스의 모든 멤버(private 포함)에 접근 가능 |
정적 내부 클래스 (static 있음) | ❌ 바깥 클래스의 인스턴스 변수에는 직접 접근 불가 (객체를 전달해야 함) |
일반 내부 클래스는 바깥 클래스의 일부분으로 포함되어 있는 클래스이기 때문에, 바깥 클래스의 private 멤버에도 접근이 가능하다.
정적 내부 클래스는 static이 아닌 동적인 멤버에는 직접적으로 접근할 수 없다.
따라서 접근하기 위해서는 개별적인 클래스처럼 바깥 클래스의 객체를 생성하고 객체를 정적 내부 클래스에 전달해주어야 한다.
클래스의 로딩 시점
- 클래스의 객체 생성 시
- 정적 메서드, 정적 변수에 처음 접근할 때
class Counter {
static int count = 0; // 클래스 변수
static {
System.out.println("Counter 클래스가 로딩되었습니다.");
}
void increment() {
count++;
}
}
public class Main {
public static void main(String[] args) {
// 클래스가 처음 사용될 때 로딩됨
System.out.println(Counter.count); // 클래스 변수에 접근
Counter c1 = new Counter(); // 클래스의 인스턴스를 생성
c1.increment();
System.out.println(Counter.count); // 클래스 변수에 접근
}
}
Counter 클래스가 로딩되었습니다. //static 블록으로 인해 처음 로드될 때 한 번 실행됨
0
1
클래스 로딩 방식
자바는 클래스를 지연 로딩(Lazy Loading)방식으로 로딩한다.
즉, 모든 클래스를 프로그램을 실행하자마자 로딩하는 방식이 아니라, 해당 클래스가 참조되는 순간 메모리에 로드되는 것이다.
그 이후는 해당 클래스가 여러 번 참조되더라도 프로그램을 재실행하지 않는 이상 다시 로딩하지 않는다.
한 번 로드된 클래스는 메모리 캐시에 유지되어 프로그램이 종료되기 전까지 꺼내어 사용할 수 있기 때문이다.
정적 메서드, 정적 변수는 로드될 때 method area에 저장되기 때문에 모든 객체가 데이터를 공유하며 상시 접근이 가능하다.
그러나 method area에 동적 데이터에 대한 정보는 선언된 틀만 존재하고, 데이터를 할당할 공간 자체가 없다.
힙에 각 객체의 동적 데이터를 저장함으로써 모든 객체는 동일한 틀을 가지면서도 각기 다른 값을 저장할 수 있는 것이다.
이러한 이유로 static이 아닌, 동적 데이터는 객체가 생성되어 힙에 저장된 순간부터 접근할 수 있다.
'언어, 프레임워크 > Java' 카테고리의 다른 글
Wrapper 클래스들의 공통 메서드 / 개별 메서드 (0) | 2025.03.02 |
---|---|
equals() 메서드 사용법 (0) | 2025.03.01 |
스트림 (Stream) 알아보기 (0) | 2025.02.27 |
익명 클래스 / 람다 (Lambda) / 함수형 인터페이스 (0) | 2025.02.26 |
Wrapper 클래스 (0) | 2025.02.25 |