[기본 개념] 1 | (5.1) 변수의 초기화

728x90

[기본 개념] 1 | (5.1) 변수의 초기화

1> 변수의 초기화

2> 명시적 초기화(explicit initialization)

3> 초기화 블럭(initialization block)

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

1. 변수의 초기화

 변수를 선언하고 처음으로 값을 저장하는 것을 '변수의 초기화'라고 한다. 멤버변수는 자동적으로 변수의 자료형에 맞는 기본값으로 초기화가 이루어지지만 지역변수는 사용하기 전에 반드시 초기화를 해야 한다.

 

        class InitTest {

            int x ;                   // 인스턴스변수

            int y = x ;              // 인스턴스변수

     

            void method1( ) {

                int i ;                // 지역변수

                int j = i ;           // error. 지역변수 초기화하지 않음

            }

        }

 

각 타입의 기본값(default value)는 다음과 같다.

 

자료형 기본값
boolean false
char '\u000'
byte, short, int 0
long 0L
float 0.0f
double 0.0d 또는 0.0
참조형 변수 null

 

> 멤버변수의 초기화 방법

1. 명시적 초기화 (explicit initialization)

2. 생성자 (constructor)

3. 초기화 블럭 (initialization block)

    - 인스턴스 초기화 블럭 : 인스턴스변수를 초기화 하는데 사용

    - 클래스 초기화 블럭    : 클래스변수를 초기화하는데 사용

2. 명시적 초기화(explicit initialization)

 변수 선언과 동시에 초기화 하는 것을 명시적 초기화라고 한다. 가장 기본적이면서도 간단한 초기화 방법이므로 여러 초기화 방법 중에서 가장 우선적으로 고려되어야 한다.

 

        class Car {

            int door = 4 ;                     // 기본형 변수의 초기화

            Engine e = new Engine ( ) ;   // 참조형 변수의 초기화

        }

 

 간단하고 명료하긴 하지만 보다 복잡한 초기화 작업이 필요할 때는 '초기화 블록(initialization block)' 또는 생성자를 사용해야 한다.

3. 초기화 블럭(initialization block)

'클래스 초기화 블럭'과 '인스턴스 초기화 블럭' 두 종류가 있다.

 

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

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

 

 초기화 블럭을 작성하려면, 인스턴스 초기화 블럭은 클래스 내에 블럭{ }을 만들고 안에 코드를 작성하면 되고 클래스 초기화 블럭은 인스턴스 초기화 블럭 앞에 단순히 static을 덧붙이기만 하면 된다.

 

        class InitBlock {

            static {  /* 클래스 초기화블럭입니다. */  }

 

            {  /* 인스턴스 초기화블럭입니다. */  }

        }

 

 클래스 초기화블럭은 클래스가 메모리에 처음 로딩될 때 한 번만 수행되며, 인스턴스 초기화블럭은 생성자와 같이 인스턴스를 생성할 때마다 수행된다. 그리고 생성자보다 인스턴스 초기화블럭이 먼저 수행된다.

 

 인스턴스 변수의 초기화는 주로 생성자를 사용하고, 인스턴스 초기화블럭은 모든 생성자에서 공통으로 수행돼야 하는 코드를 넣는다.

 

        Car ( ) {

            count++ ;

            serialNo = count ;

            color = "white" ;

            gearType = "Auto" ;

        }

        Car(String color, String gearType) {

            count++ ;

            serialNo = count ;

            this.color = color ;

            this.gearType = gearType ;

        }

 

위와 같이 클래스의 모든 생성자에 공통으로 수행되는 문장을 인스턴스 블럭에 넣어주면 간결해진다.

 

        {

            count++ ;                       // 인스턴스 초기화블럭

            serialNo = count ;

        }

       

        Car ( ) {

            color = "white" ;

            gearType = "Auto" ;

        }

        Car(String color, String gearType) {

            this.color = color ;

            this.gearType = gearType ;

        }

 

예제/BlockTest.java

public 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();
    }
}
실행결과

static {  }
BlockTest bt = new BlockTest(); 
{  }
생성자
BlockTest bt2 = new BlockTest(); 
{  }
생성자

 

 예제가 실행되면서 BlockTest가 메모리에 로딩될 때, 클래스 초기화블럭이 가장 먼저 수행되어 'static{ }'이 화면에 출력된다. 그 다음 main메서드가 수행되어 BlockTest인스턴스가 생성되면서 인스턴스 초기화블럭이 먼저 수행되고 끝으로 생성자가 수행된다.

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

 초기화가 수행되는 시기와 순서에 대해 정리해보자.

 

클래스변수의 초기화 시점        클래스가 처음 로딩될 때 단 한번 초기화된다.

인스턴스변수의 초기화 시점   인스턴스가 생성될 때마다 각 인스턴스 별로 초기화가 이뤄진다.

 

클래스변수 초기화순서            기본값 - 명시적초기화 - 클래스 초기화블럭

인스턴스변수의 초기화순서    기본값 - 명시적초기화 - 인스턴스 초기화블럭 - 생성자

 

        class InitTest {

            static int cv = 1 ;    // 명시적 초기화

            int iv = 1 ;

 

            static {         cv = 2 ;        }    // 클래스 초기화블럭

            {        iv = 2 ;        }             // 인스턴스 초기화블럭

            InitTest ( ) {                         // 생성자

                iv = 3 ;

            }

        }

 

 위 InitTest클래스는 클래스변수(cv)와 인스턴스변수(iv)를 하나씩 가지고 있다. 'new InitTest( );'와 같이 하여 인스턴스를 생성했을 때, cv와 iv가 초기화되어가는 과정을 자세히 살펴보도록 하자.

 

클래스 초기화 인스턴스 초기화
기본값 명시적 초기화 클래스
초기화블럭
기본값 명시적 초기화 인스턴스
초기화블럭
생성자
cv [ 0 ]

cv [ 1 ]

cv [ 2 ]

cv [ 2 ]
iv [ 0 ]
cv [ 2 ]
iv [ 1 ]
cv [ 2 ]
iv [ 2 ]
cv [ 2 ]
iv [ 3 ]
2 3 4 5 6 7

 

> 클래스변수 초기화 ( 1 ~ 3 )     : 클래스가 처음 메모리에 로딩될 때 차례대로 수행됨

> 인스턴스변수 초기화 ( 4 ~ 7 )  : 인스턴스를 생성할 때 차례대로 수행됨

 

예제/ProductTest.java

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

    {
        ++count;            // Product인스턴스가 생성될 때마다 1씩증가시켜 serialNo에 저장
        serialNo = count;
    }
}

public 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 + "개 입니다.");
    }
}
실행결과
    
p1의 제품번호(serial no)는 1
p2의 제품번호(serial no)는 2
p3의 제품번호(serial no)는 3
생산된 제품의 수는 모두 3개 입니다.

 Product클래스의 인스턴스를 생성할 때마다 인스턴스 블럭이 수행되어, 클래스변수 count의 값을 1 증가시킨 다음, 그 값을 인스턴스변수 serialNo에 저장한다.

 

 만약 count를 인스턴스변수로 선언했다면, 인스턴스가 생성될 때마다 0으로 초기화될 것이므로 모든 Product인스턴스의 serialNo값은 항상 1이 될 것이다.

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90