[Java/자바] 멤버변수 초기화 방법 (명시적 초기화, 초기화 블럭)

아래의 포스팅을 통해 멤버변수가 무엇인지, 지역변수가 무엇인지에 대해 알아보았습니다.

 

(Java/자바) 클래스 변수, 인스턴스 변수, 지역 변수란?

이 글을 읽기 앞서 자바의 클래스와 객체란? 인스턴스란 ? 무엇인지 모른다면 아래 포스팅을 참고하시면 좋습니다. (Java/자바) 클래스와 객체 클래스와 객체 클래스와 객체를 설명하는 예시로 여

hstory0208.tistory.com

 

다시 한번 간단하게 복습하자면 다음과 같습니다.

멤버변수(클래스변수, 인스턴스변수)와 배열의 초기화는 선택적이지만, 지역변수의 초기화는 필수적이다.

 

이번 시간에는 멤버변수의 초기화의 방법들에 대해 알아보고자 합니다.

 

멤버변수의 초기화 방법으로는 총 3가지가 있습니다.

  1. 명시적 초기화
  2. 생성자
  3. 초기화 블럭 - 인스턴스 초기화 블럭, 클래스 초기화 블럭

이 중 생성자에 대해서는 아래 포스팅에 자세히 설명되어 있으니 참고하면 되며,

 

[Java/자바] 생성자( Constructor )란 ?

생성자 ( Constructor ) 생성자는 new 연산자를 통해 인스턴스가 생성될 때 호출되고 제일 먼저 실행되는 "인스턴스 초기화 메서드" 입니다. 어떻게 보면 메서드와 비슷해보이지만 생성자는 단순히

hstory0208.tistory.com

 

명시적 초기화와 초기화 블럭에 대해 알아보겠습니다.

 


명시적 초기화

변수를 선언과 동시에 초기화하는 것을 "명시적 초기화"라고 합니다.

가장 기본적이면서도 간단한 초기화 방법입니다.

class Car {
	int door = 4;	// 기본형 변수의 초기화
    	Engine e = new Engine(); 	// 참조형 변수의 초기화
    
    ...
}

 

명시적 초기화는 이처럼 간단한 초기화가 필요할 시 사용하며,

보다 복잡한 초기화 작업이 필요할 때는 "초기화 블럭"또는 생성자를 이용합니다.

 


초기화 블럭

초기화 블럭에는 "클래스 초기화 블럭"과 "인스턴스 초기화 블럭" 두 가지가 있습니다.

클래스 초기화 블럭 - 클래스 변수의 복잡한 초기화에 사용
인스턴스 초기화 블럭 - 인스턴스 변수의 복잡한 초기화에 사용

 

인스턴스 초기화 블럭단순히 클래스 내에 블럭 { }을 만들고 그 안에 코드를 작성하면됩니다.

클래스 초기화 블럭은 이전 클래스 변수나 메서드 처럼 블럭 {} 앞에 static 붙이기만 하면 클래스 초기화 블럭이 됩니다.

Class BlockTest {
	 /* 클래스 초기화 블럭 */
	static { }
    
        /* 인스턴스 초기화 블럭 */
        { }

}

 

클래스 초기화 블럭은 클래스가 메모리에 처음 로딩될 때 한번만 수행되고,

인스턴스 초기화 블럭 생성자와 같이 인스턴스를 생성할 때 마다 수행됩니다.

 

초기화 블럭의 사용

인스턴스 변수의 초기화는 주로 생성자를 사용하고,

인스턴스 초기화 블럭 모든 생성자에서 공통으로 수행되어야 하는 코드를 넣는데 사용합니다.

 

위와 같이 두 가지의 생성자가 있는데 이 두 생성자에서 아래 두 코드가 중복됩니다.

 

이 중복된 코드를 초기화 블럭을 이용하여 수정하면 아래와 같습니다.

/* 인스턴스 초기화 블럭 = 두 생성자가 공통으로 수행하는 코드를 넣었다.  */
{
	count++;
        serialNo = count;
}

Car() {
	color = "White";
        gearType = "Auto";
}

Car(String color, String gearType) {
	this.color = color;
        this.gearType = gearType;
}

 

초기화 블럭 Test 코드
class BlockTest {

	// 클래스 초기화 블럭
	static {
		System.out.println("static { 클래스 초기화 블럭 }");
	}

	// 인스턴스 초기화 블럭
	{
		System.out.println("{ 인스턴스 초기화 블럭 }");
	}

	public BlockTest() {     
		System.out.println("생성자");
	}

	public static void main(String args[]) {
		System.out.println("BlockTest bt = new BlockTest(); ");
		BlockTest bt = new BlockTest();

		System.out.println("BlockTest bt2 = new BlockTest(); ");
		BlockTest bt2 = new BlockTest();
	}
}

출력 결과

 

  • 위의 코드를 실행하게 다음과 같은 순서로 작업이 수행됩니다.

1. BlockTest가 메모리에 로딩될 때, 클래스 초기화 블럭이 가장 먼저 한 번 수행되어 "static { 클래스 초기화 블럭 }"이 출력됩니다.

2. 그 다음 main 메서드가 수행되어 bt 인스턴스가 생성되고 ( "BlockTest bt = new BlockTest(); " ) , 인스턴스 초기화 블럭이 수행되고, 끝으로 생성자가 수행됩니다.

 

멤버변수의 초기화 시점
클래스변수 : 클래스가 처음 로딩될 때 단 한번 초기화.
인스턴스변수 : 인스턴스가 생성 될 때마다 각 인스턴스별로 초기화.

멤버변수의 초기화 순서
클래스변수 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭
인스턴스변수 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자

 

 


초기화 블럭 예시 코드

 

클래스 변수의 초기화

클래스 변수인 배열 arr를 명시적 초기화를 통해 생성하고, 

arr 변수에 클래스 초기화 블럭을 이용하여 다음과 같이 랜덤한 값을 채웁니다. 

class StaticBlockTest 
{
	static int[] arr = new int[10];

	static {
		for(int i=0;i<arr.length;i++) {
			// 1과 10사이의 임의의 값을 배열 arr에 저장한다.
			arr[i] = (int)(Math.random()*10) + 1;
		}
	}

	public static void main(String args[]) {
		for(int i=0; i<arr.length;i++)
			System.out.println("arr["+i+"] :" + arr[i]);
	}
}

출력 결과

 

 

제품생산 코드 

공장에서 제품을 생산할 때 제품마다 제품번호를 부여하는 것과 같은 코드입니다.

인스턴스 블럭은 인스턴스가 생성될 때마다 수행되므로, 새 인스턴스가 생성될 때마다 serialNo는 1씩 증가합니다.

class Product {
	static int count = 0;   // 생성된 인스턴스의 수를 저장하기 위한 변수
	int serialNo;	        // 인스턴스 고유의 번호

	// 인스턴스가 생성될 때마다 인스턴스 블럭이 수행된다.
	{
		++count;
		serialNo = count;
	}

	public Product() {}     // 기본생성자, 생략가능
}

class ProductTest {
	public static void main(String args[]) {
		Product p1 = new Product();
		Product p2 = new Product();
		Product p3 = new Product();

		System.out.println("p1의 제품번호(serial no)는 " + p1.serialNo);
		System.out.println("p2의 제품번호(serial no)는 " + p2.serialNo);
		System.out.println("p3의 제품번호(serial no)는 " + p3.serialNo);
		System.out.println("생산된 제품의 수는 모두 "+Product.count+"개 입니다.");  
	}
}

출력 결과

 

 


참고자료 : 자바의 정석3