본문 바로가기

Java

[Java] static 초기화 블록

최근 static 초기화 블록이 헷갈리는 일이 있어서 이참에 정리하려고 한다.

 

초기화 블록은 클래스 내의 멤버변수를 명시적 초기화보다 복잡한 초기화를 할 때 사용되는 방법이다.

초기화블록은 static 초기화 블록과 일반 초기화 블록이 있다. 이 둘을 각 각 클래스 초기화 블록 과 인스턴스 초기화 블록

이라고 한다. 

 

클래스 초기화 블록

클래스 초기화 블록의 선언은 static { } 이런 식으로 하고, 클래스가 로딩되는 시점에 한 번만 실행된다.   

인스턴스가 생성되면 heap에 인스턴스의 크기만큼 메모리가 잡히고 초기화 블록이 멤버변수들의 초기화를 수행한다. 그다음에 생성자가 실행된다.

 

인스턴스 초기화 블록

인스턴스 초기화 블록은 { } 이런 식으로 선언한다. 인스턴스 초기화 블록은 모든 생성자들이 공통적으로 실행하는 코드를 인스턴스 초기화 블록에 넣어 코드의 중복을 막는 역할을 한다.

인스턴스 초기화 블록은 클래스 초기화 블록과는 달리 인스턴스가 생성되는 시점마다 실행된다. 

 

 

클래스 초기화 블록과 인스턴스 초기화 블록의 차이점을 알아보는 예제이다.

public class StaticExam {

	public static int staticInt;
	public static int a;

	static {
		for (int i = 0; i <= 10; i++) {
			staticInt += i;
		}
	}

	{
		for(int i = 0; i <= 10; i++) {
			a += i;
		}
	}

	public StaticExam() {;}
			
}

 

public class Test {

	public static void main(String[] args) {
		
		System.out.println("클래스를 메모리에 로딩 시켰다.");
		Class Exam = new StaticExam().getClass();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println();
				
		
		System.out.println("두 번째 인스턴스 생성");
		new StaticExam();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println("인스턴스 초기화 블록: " + StaticExam.a);
		System.out.println();
		
		System.out.println("세 번째 인스턴스 생성");
	    new StaticExam();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println("인스턴스 초기화 블록: " + StaticExam.a);
		System.out.println();
	}
}
//	실행 결과
//	클래스를 메모리에 로딩 시켰다.
//	클래스 초기화 블록: 55
//	
//	두 번째 인스턴스 생성
//	클래스 초기화 블록: 55
//	인스턴스 초기화 블록: 110
//	
//	세 번째 인스턴스 생성
//	클래스 초기화 블록: 55
//	인스턴스 초기화 블록: 165

위의 예제에서 알 수 있듯이 클래스 초기화 블록으로 초기화를 한 staticInt 변수는 처음 값 그대로 인 것을 알 수 있지만 인스턴스 초기화 블록으로 초기화를 한 멤버변수 a는 인스턴스를 생성할 때마다 값이 달라지는 것을 확인할 수 있다.

 

 

그다음엔 위의 에제를 조금 변형해서 초기화 순서를 알아보겠다.

그전에 미리 말하자면 명시적 초기화 → 초기화 블록 → 생성자 순으로 실행된다. 정말 그런지 확인해 보자!

 

public class StaticExam {

	public static int staticInt;
	public static int a;
	public int b;   

	static {
		for (int i = 0; i <= 10; i++) {
			staticInt += i;
		}
	}

	{
		for(int i = 0; i <= 10; i++) {
			a += i;
		}
		b = a;
	}

	public StaticExam() {
		b = 1;
	}
			
}

 

public class Test {

	public static void main(String[] args) {
		
		System.out.println("클래스를 메모리에 로딩 시켰다.");
		Class Exam = new StaticExam().getClass();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println();
				
		
		System.out.println("두 번째 인스턴스 생성");
		StaticExam ex1 = new StaticExam();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println("인스턴스 초기화 블록: " + StaticExam.a);
		System.out.println("생성자 " + ex1.b);
		
		System.out.println();
		
		System.out.println("세 번째 인스턴스 생성");
		StaticExam ex2 = new StaticExam();
		System.out.println("클래스 초기화 블록: " + StaticExam.staticInt);
		System.out.println("인스턴스 초기화 블록: " + StaticExam.a);
		System.out.println("생성자 " + ex2.b);
		System.out.println();
	}
}
//	실행 결과
//	클래스를 메모리에 로딩 시켰다.
//	클래스 초기화 블록: 55
//	
//	두 번째 인스턴스 생성
//	클래스 초기화 블록: 55
//	인스턴스 초기화 블록: 110
//	생성자 1
//	
//	세 번째 인스턴스 생성
//	클래스 초기화 블록: 55
//	인스턴스 초기화 블록: 165
//	생성자 1

이번 예제에서는 멤버변수  b를 추가하고 초기화 블록에서 b를 a로 초기화를 했다. 그리고 생성자에서는 b의 값을 1로 덮어 씌웠다.  만약 초기화 블록 다음에 생성자가 나오면 b의 값은 1이 될 것이고, 생성자 다음에 초기화 블록이 실행된다면 a랑 b의 값이 같을 것이다. 실행 결과를 보면 b의 값이 1인 것을 보아 초기화 블록 다음에 생성자가 실행된다는 것을 확인할 수 있다.  

'Java' 카테고리의 다른 글

[Java] BigInteger  (0) 2023.07.10
[Java] 정규표현식  (0) 2023.06.27
[Java] java.util.Objects를 이용한 NPE방어  (0) 2023.06.23
[Java] Wrapper Class  (0) 2023.06.21
[자바] 쉬프트 연산자  (0) 2023.06.15