Post

변수 초기화와 초기화 블록

변수 초기화

변수의 초기화는 변수를 사용할 때 선언과 함께 필요한 작업 중 하나이다.

변수 초기화는 지역 변수(메소드 안에서 사용하는 변수)에서는 필수적으로 필요하지만, 멤버변수(스태틱, 인스턴스 변수)에는 선택적으로 사용 가능하다.

1
2
3
4
5
6
7
8
9
public class Main { //
    int i; // 가능
    static int i; // 가능
    int i = 0; // 가능
    public static void main(String[] args) {
        int i; // 오류
        int i = 0; // 완료
    }
}

초기화 블록

초기화 블록은 Static 초기화 블록과 Instance 초기화 블록으로 나뉜다. 초기화 블록은 클래스가 처음 로딩 될 때 제일 먼저 실행된다.

Static 초기화 블록 = static {}

Instance 초기화 블록 = {}

이와 같이 구분할 수 있다.

하지만 Instance 초기화 블록의 경우 생성자와 큰 차이는 없기 때문에 잘 사용되지 않지만, 여러 생성자에 공통적으로 들어가는 중복 코드가 있을 시 코드를 줄이기 위해 사용된다.

Static 초기화 블록

Static 초기화 블록의 경우는 클래스 로딩 시 한번만 실행된다. 주로 클래스 변수를 초기화 시키는 코드를 둔다.

아래 예제를 보며 Static 초기화 블록의 실행 순서에 대해 공부하자.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class Exam0691 {
  static class A {
    static int a = 7;
    static {
      System.out.println("A.static{}");
      a += B.b;
    }
  }
  static class B {
    static int b = 22;
    static {
      System.out.println("B.static{}");
      b += A.a;
    }
  }
  public static void main(String[] args) {
    System.out.println(A.a); // ?
    System.out.println(B.b); // ?

위 예제를 보고 출력 값이 얼마가 나오는지 예상해보자

참고할 점 : 스태틱 블록은 클래스 맴버를 만났을 때 로딩이 시작된다.

해석

클래스 맴버를 만났을 때 클래스 로딩이 시작 된다는 점을 주의하자

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class Exam0691 {
  static class A {
    static int a = 7;
    static {
      System.out.println("A.static{}");
      a += B.b;
    }
  }
  static class B {
    static int b = 22;
    static {
      System.out.println("B.static{}");
      b += A.a;
    }
  }
  public static void main(String[] args) {
    System.out.println(A.a);
    System.out.println(B.b);
  }

위 소스 코드에서 처음 main 문에 들어가 시작하고 처음 만나는 코드는 클래스 A의 a 값을 불러오라는 출력문이다.

이때 바로 클래스 A에 대한 로딩이 시작된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
  public static void main(String[] args) {
    System.out.println(A.a); // 클래스 A 로딩 시작
    System.out.println(B.b);
  }

static class A {
    // static int a = 7;
    static {
      a = 7; // 위의 변수를 선언하고 초기화 하는 부분은 로딩이 시작되면 한 블록으로 취급됨
      System.out.println("A.static{}");
      a += B.b;
    }
  }
 
// 위 클래스는 아래 처럼 로딩된다.
a = 7
A.static{} 출력
a = a + B.b // 이 부분에서 클래스 B가 처음 로딩된다. 
    
static class B {
    //static int b = 22;
    static {
      b = 22;
      System.out.println("B.static{}");
      b += A.a;
    }
  }

// 위 클래스는 아래 처럼 로딩

b = 22;
B.static{} 출력
b = b + A.a // 이때 이미 클래스 A의 경우 로딩이 끝남. 그러므로 a = 7
//그 결과
b = 29 된다

//다음으로 B 클래스의 로딩이 끝났기 때문에 B 클래스 로딩이 시작된 지점으로 돌아간다.
    static class A {
    // static int a = 7;
    static {
      a = 7; 
      System.out.println("A.static{}");
      a += B.b; // 클래스 B 로딩 시작 지점
    }
  }
a = a + B.b // 이 지점으로 다시 돌아가 연산을 시작된다. 클래스 B의 로딩이 끝난 상태. 이때 각 변수의 값은 b = 29, a = 7
// 그 결과
a = 7 + 29 // a = 36이 된고, 클래스 A의 로딩이 끝나 시작된 지점으로 돌아감
    
public static void main(String[] args) {
    System.out.println(A.a); // 클래스 A 로딩 시작지점
    // 이때 주의할 점은 스태틱 클래스 로딩은 한번만 일어나며, 해당 클래스가 먼저 실행된 뒤, 그 다음 클래스 로딩 시작 지점의 코드가 실행됨
    System.out.println(B.b); // 이미 로딩이 끝나 바로 B.b 값이 출력
 }    
 

결과

1
2
3
4
A.static{}
B.static{}
36
29

이렇듯 클래스 블록이 로딩되는 순서에 대해 조심해야한다.

Instance 초기화 블록

Instance 초기화 블록의 경우 생성자와 마찬가지로 인스턴스가 생성될 때마다 실행된다. 하지만 언제나 Instance 초기화 블록이 생성자보다 먼저 실행된다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class Car {

    private String modelName;
    private int modelYear;
    private String color;
    private int maxSpeed;
    private int currentSpeed;
    // 변수 초기화

    { // 인스턴스 초기화 블록
        this.currentSpeed = 0;
    }

    Car() {} // 기본 생성자

    Car(String modelName, int modelYear, String color, int maxSpeed) {
        this.modelName = modelName;
        this.modelYear = modelYear;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    public int getSpeed() {
        return currentSpeed;
    }
}

public class Member03 {
    public static void main(String[] args) {
        Car myCar = new Car();                // 인스턴스 생성
        System.out.println(myCar.getSpeed()); // 인스턴스 메소드의 호출
    }
}

결과 = 0 이 출력된다. 위와 같이 작성한다면 Car(String modelName, int modelYear, String color, int maxSpeed) 의 생성자가 다양한 값을 받고 여러번 실행될 때 그 영향을 받지 않고 고정된 값을 출력할 수 있다. 이렇듯 한 변수의 값을 고정하거나, 공통된 부분을 분리하고 싶다면 Instance 초기화 블록을 사용하면 코드의 중복을 줄일 수 있다.

출처) 초기화 블록

This post is licensed under CC BY 4.0 by the author.