변수 초기화와 초기화 블록
변수 초기화
변수의 초기화는 변수를 사용할 때 선언과 함께 필요한 작업 중 하나이다.
변수 초기화는 지역 변수(메소드 안에서 사용하는 변수)에서는 필수적으로 필요하지만, 멤버변수(스태틱, 인스턴스 변수)에는 선택적으로 사용 가능하다.
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 초기화 블록을 사용하면 코드의 중복을 줄일 수 있다.
출처) 초기화 블록