[Java] 정적 멤버 선언 (static 필드, static 메서드, 정적 코드 블록)

해로(haero77)·2022년 7월 25일
0

Java 문법

목록 보기
8/15
post-thumbnail

✍ 본 포스팅은 책 ‘처음 해보는 자바 프로그래밍(오정임 저, 루비페이퍼)’을 참고하여 작성되었습니다.

정적 멤버(static member) 선언

  • static member : 모든 인스턴스가 공유하는 멤버. static 키워드를 이용하여 변수를 선언.

  • 정적 멤버에는 클래스 필드(=static 필드), 클래스 메서드(=static 메서드), 정적 코드 블럭 이 있다.

static int total Count; // static 필드

public static void print1() { // static 메서드
	System.out.println("hello");
}

static { // 정적 코드 블럭
	System.out.println("hello");
	System.out.println("java");
} 

클래스 필드


class Count {
	public static int totalCount; // 클래스 필드. 프로그램 실행 시 코드(영역) 메모리에 할당
	int count; // 인스턴스 필드. 인스턴스 생성 시 힙(영역) 메모리에 할당
}
  • 필드 선언 시 static 키워드를 붙여 클래스 필드를 선언한다.

  • static 키워드를 붙여서 선언하였으므로, 프로그램 실행 시(메모리 할당 시점) 자동으로 코드 메모리(=메서드 메모리)에 할당되고, 프로그램 종료 시 메모리 해제가 된다.

    • 인스턴스 필드는 인스턴스 생성 시(메모리 할당 시점) 힙 메모리에 할당되고, 인스턴스 소멸 시 메모리 해제가 된다.

메모리 관점에서 보는 클래스 필드와 인스턴스 필드의 차이

/* 클래스 필드와 인스턴스 필드 비교 예제 */

// 하나의 소스파일에 여러 개의 클래스 선언이 가능하다.
// 단 소스 파일 이름은 public 으로 선언한 클래스 이름으로 지정해야한다.
class Count {
    public static int totalCount; // 클래스 필드. 프로그램 시작 시 코드 메모리에 생성됨.
    int count; // 인스턴스 필드. 인스턴스 생성 시 힙 메모리에 생성됨.
}

public class CountTest {
    public static void main(String[] args) {
        System.out.println("실행 시작");
        Count c1 = new Count(); // 참조변수 c1은 스택 메모리에 생성. c1이 가리키는 인스턴스는 힙 메모리에 생성.
    }
}

위 예제를 통해 프로그램이 실행되는 동안 각 필드와 변수들이 어느 메모리에 생성되는지를 이해해보자.

  • JVM의 클래스 로더는 main( ) 메서드가 시작되기 전에 로딩된 모든 클래스 코드를 살펴보고 static으로 선언된 정적 멤버를 코드 메모리에 할당한다.

    • 위 예제의 클래스 필드 totalCount 가 static으로 선언되었으므로, 메모리의 코드 영역에 할당된다.
  • main( ) 메서드가 실행되고, new Count( ); 명령문을 통해 Count 클래스의 인스턴스가 힙 메모리에 생성된다.

    • 이 때, 해당 클래스에 선언된 필드도 함께 할당하는데, static 키워드가 붙은 클래스 필드 totalCount는 힙 메모리에 할당하지 않는다(인스턴스 필드 count는 힙 메모리에 할당된다). 클래스 필드는 이미 main( ) 메서드가 실행되기 전에 코드 메모리에 할당했기 때문이다.
    • 생성된 Count 인스턴스는 클래스 필드를 직접적으로 포함하지는 않고, ‘코드 메모리에 할당된 클래스 필드의 정보’를 포함한다.
  • 참조형 데이터 타입 Count 로 선언한 참조 변수 c1은 스택 메모리에 생성되고, 힙 메모리에 있는 Count 인스턴스를 참조한다.


클래스 필드 사용

  • 클래스 필드를 사용할 때는 참조변수가 필요 없다. main( ) 메서드가 실행되기 전에 이미 메모리에 할당되었으므로 바로 사용 가능하다.

  • 클래스 필드는 클래스명.필드명 과 같이 사용한다.


클래스 메서드(static 메서드)


클래스 메서드란?

  • 메서드 선언부에 static 키워드가 선언된 메서드를 클래스 메서드라고한다.

  • static 으로 선언되었으므로, main( ) 메서드가 실행되기 전에 코드(메서드) 메모리 영역에 생성되어 사용 준비가 완료된다.

  • (사용 이유) 인스턴스 생성과 무관하게 사용하는 메서드는 static으로 선언한다.


클래스 메서드 사용

  • 클래스 메서드는 클래스명.메서드명 과 같이 사용한다.

클래스 메서드에서는 인스턴스 필드와 인스턴스 메서드를 사용할 수 없다.

  • 클래스 메서드에서는 인스턴스 필드와 인스턴스 메서드를 사용할 수 없다.

  • 클래스 메서드는 인스턴스를 생성하지 않고 사용이 가능하지만, 인스턴스 필드와 인스턴스 메서드는 인스턴스 생성 이후에 사용가능하므로, 클래스 메서드에서 인스턴스 필드와 인스턴스 메서드를 사용할 수 없다 (클래스 메서드를 호출 시 인스턴스가 생성되어 있지 않을 수 있으므로).

  • 인스턴스 메서드에서는 인스턴스 필드를 사용할 수 있다 (인스턴스 메서드 호출 시에는 이미 인스턴스가 생성되고 인스턴스 필드 역시 메모리에 생성되어있으므로)

/* 클래스 메서드와 인스턴스 메서드에서의 인스턴스 필드 사용 가능 여부 확인 예제 */
public class StaticMethodTest {
    int num = 123; // 인스턴스 필드. 인스턴스 생성된 후 사용 가능하다.

    public static void main(String[] args) {
        StaticMethodTest.print1();
        StaticMethodTest exam = new StaticMethodTest();
        exam.print2();
    }

    public static void print1() { // static 메서드
        /*
            인스턴스 필드는 인스턴스를 생성한 후에 사용 가능하므로,
            인스턴스 생성 전에 사용가능한 static 메서드에서는 인스턴스 필드와 인스턴스 메서드를 사용할 수 없다.
         */
        int num2 = num; // 오류! : static 메서드에서는 인스턴스 필드 사용 불가능
        System.out.println("hello");
    }

    public void print2() { // 인스턴스 메서드
        /*
            인스턴스 메서드를 호출하는 시점에서는 이미 인스턴스가 생성되어 인스턴스 필드가 준비되어 있는 상태이므로,
            인스턴스 메서드 내부에서는 인스턴스 필드의 사용이 가능하다.
         */
        int num3 = num; // 인스턴스 필드 사용
        System.out.println();
    }
}

정적 코드 블록


public class StaticBlockTest {
    // 정적 코드 블록. main() 메서드가 실행되기 전에 딱 한 번 실행된다.
    static {
        System.out.println("hello");
        System.out.println("java");
    }

    public static void main(String[] args) {
        System.out.println("world!");
    }
}

/*  
    (실행 결과)
    hello
    java
    world!
 */
  • 정적 코드 블록 : static 으로 선언된 실행문 블럭

  • 정적 멤버 처럼 main( ) 메서드가 실행되기 전에 딱 한 번 실행된다.

  • 프로그램이 실행될 때 먼저 처리해야하는 작업을 정적 코드 블록에 작성한다.

    • 예) static으로 선언한 클래스 필드의 초기화
profile
Every Run, Learn Counts.

0개의 댓글