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이 아닌, 동적 데이터는 객체가 생성되어 힙에 저장된 순간부터 접근할 수 있다.