본문 바로가기
Language/Java

변수의 초기화, 초기화 블럭

by 계범 2022. 3. 2.

변수의 초기화

변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 한다.

 

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

 

class InitTest{
	int x;     //인스턴스변수
    int y = x; //인스턴스 변수
    
    void method(){
    	int i;     // 지역변수
        int j = i; // 에러. 지역변수 i를 초기화하지 않고 사용
    }
}

 

멤버변수의 초기화 방법

 

1. 명시적 초기화

2. 생성자

3. 초기화 블럭

 

명시적 초기화(explicit initialization)

변수를 선언과 동시에 초기화하는 것.

 

class Car{
	int door = 4;
    Engine e = new Engine();
}

명시적 초기화는 간단하고 명료하지만, 복잡한 초기화 작업이 필요할 땐 '초기화  블럭' 또는 생성자를 사용해야 한다.

 

초기화 블럭(initialization block)

클래스 초기화 블럭 : 클래스변수의 복잡한 초기화에 사용된다.
인스턴스 초기화 블럭 : 인스턴스변수의 복잡한 초기화에 사용된다.

초기화 블럭 작성방법은, 단순히 클래스 내에 블럭{}을 만들고 그 안에 코드를 작성하기만 하면 된다.

static을 붙이면 클래스 초기화 블럭이 된다.

 

class InitBlock{
	static { /* 클래스 초기화블럭 */}
    { /* 인스턴스 초기화블럭 */}
    
    //...
}

 

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

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

 

그리고 생성자보다 인스턴스 초기화 블럭이 먼저 수행된다는 사실도 기억해두자.

 

 인스턴스 초기화 블럭은 코드의 중복을 제거해준다. 오버로딩된 생성자마다 해야할 코드들을 인스턴스 초기화블럭으로 빼서 쓰면 된다.

 

중복을 제거하는 것은 코드의 신뢰성을 높여주고, 오류의 발생가능성을 줄여 준다는 장점이 있다.

 

class BlockTest {

	static {
		System.out.println("static { }");
	}

	{
		System.out.println("{ }");
	}

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

	public static void main(String args[]) {
		BlockTest bt = new BlockTest();
	}
}

실행순서

1. 클래스 초기화 블럭 수행 "static {}"

2. main 메서드 수행되어 BlockTest인스턴스 생성되면서 인스턴스 초기화 블럭 수행 "{}"

3. 생성자 수행 "생성자"

 

멤버변수의 초기화 시기와 순서

클래스변수 : 클래스가 처음 로딩될 때 단 한번 초기화
인스턴스변수 : 인스턴스가 생성될 때마다 각 인스턴스별로 초기화
클래스변수의 초기화 순서 : 기본값 -> 명시적초기화 -> 클래스 초기화 블럭
인스턴스변수의 초기화순서 : 기본값 -> 명시적초기화 -> 인스턴스 초기화 블럭 -> 생성자
class InitTest{
	static int cv = 1;  //명시적 초기화부분
    int iv = 1;
    
    static { cv = 2; } // 클래스 초기화 블럭
    { iv = 2; } // 인스턴스 초기화 블럭
    
    InitTest(){ // 생성자
    	iv = 3;
    }
}

 

클래스 초기화 인스턴스 초기화
기본값 명시적 초기화 클래스
초기화 블럭
기본값 명시적 초기화 인스턴스
초기화 블럭
생성자
cv 0 cv 1 cv 2 cv 2 cv 2 cv 2 cv 2
      iv 0 iv 1 iv 2 iv 3
1 2 3 4 5 6 7

클래스변수 초기화: 클래스가 처음 메모리에 로딩될 때 차례대로 수행

인스턴스변수 초기화: 인스턴스를 생성할 때 차례대로 수행

 

1. cv가 메모리(method area)에 생성되고, cv에는 int형의 기본값 0이 cv에 저장된다.

2. 명시적 초기화(int cv = 1)에 의해 cv에 1이 저장된다.

3. 마지막으로 클래스 초기화 블럭(cv = 2) 수행되어 cv에 2가 저장된다.

4. InitTest클래스의 인스턴스가 생성되면서 iv가 메모리(heap)에 존재하게 된다. iv도 기본값 0이 저장된다.

5. 명시적 초기화에 의해 iv에 1이 저장된다.

6. 인스턴스 초기화 블럭에 의해 iv에 2가 저장된다.

7. 마지막으로 생성자에 의해 iv에는 3이 저장된다.

 

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+"개 입니다.");  
	}
}

 

인스턴스를 생성할때마다 인스턴스 초기화 블럭에 의해 count가 증가함.

그로 인해 각 제품이 다른 serialNo를 가지게 된다.

 

참조

'Java의 정석' 책

댓글