음... a는 초기화가 선언되지 않았으니 디폴트 값 0일 테고 b는 a에서 1 올린 값과 같아지니 b = 1 가 될 테고 c값은 1인 a를 다시 1 올린 값과 같아지니 c = 2 이 돼서 a = 2, b = 1 c = 2 가 되겠구나!라고 생각할 수 있습니다.
그런데 말이죠. 실제로 값을 보니 a =2, b = 2, c = 1입니다 응? 왜 b랑 c의 값이 왜 이러지 라고 생각할 수 있을 것입니다.
사실은 그렇습니다. 클래스 변수와 인스턴스 변수들 중 항상 클래스 변수가 먼저 초기화된 뒤에 인스턴스 변수가 초기화됩니다. 바로 이 부분이 오늘의 핵심 내용인 거죠.
보다 정확하게 말하면 클래스 변수는 클래스가 메모리에 올라갈 때 선언되고 인스턴스 변수는 객체가 생성될 때 실행됩니다. 그래서 객체 1을 선언하기 전 이미 a = 1 , c = 1입니다.
이를 확인하기 위해 객체를 생성하지 않은 채 아래의 코드를 메인에다가 입력하면 System.out.println("a = "+variable_lecture.a); System.out.println("b = "+variable_lecture.c);
a = 1 c = 1 이 출력이 됩니다.
이제 객체를 생성하겠습니다. int b = ++a 코드가 실행됩니다. 결과적으로 a = 2, b = 2, c = 1 이 됩니다.
그럼 다시 한번 객체를 생성해보겠습니다. 이제 객체는 총 2개입니다. 그렇다면 2번째 객체를 생성하고 난 뒤의 a, b, c 값은 어떻게 될까요? 그전에 다시 한번 클래스 변수와 인스턴스 변수에 대해 복습해 보자면 클래스 변수는 클래스가 메모리에 올라갈 때 선언되며 모든 객체가 공통으로 가지는 값이라고 했고 인스턴스 변수는 객체가 생성될 때 각 객체마다 가지는 독립적인 값입니다.
2번째 객체를 생성했습니다. 과연 a, b, c의 값이 어떻게 변했을까 살펴보도록 합시다.
일단 2번 객체에서 나온 값은 a =3, b = 3, c = 1입니다. 왜 그런 걸까요? 사실은 이미 객체 1개를 생성하기도 전에 static int a; static int c = ++a; 는 선언되었기 때문에 객체가 생성된다고 다시 이 코드가 실행되지 않습니다. 분명히 클래스가 메모리에 올라갈 때 한번 실행되기 때문이죠.
그래서 객체 2가 생성될 때 int b = ++a; 코드만 실행됩니다. 앞서 a = 2 가 됐기 때문에 b = 3 , a = 3 이 됩니다.
다시 한번 이전에 생성했던 객체 1을 살펴보겠습니다. 분명히 a = 2, b = 2, c = 1 이였는데...
응???? a = 3 이 되었습니다. 근데 b = 2 여전히 변함없습니다. 네 또 한번 말하자면 클래스 변수는 모든 객체가 공통으로 가지는 값입니다. 객체 2로 인해 클래스 변수 a = 3 이 되었고 이는 객체 1 에도 영향을 주기 때문이죠.
즉 객체 1이 생성된 후 클래스 변수 a = 2, c = 1입니다. 그리고 객체 2를 생성할 때 a = 2 , c = 1 인 상태에서 시작하게 됩니다. 반대로 인스턴스 변수 b는 값이 초기화되지 않은 상태인 b = 0에서 새로 시작하게 됩니다.
그리고 마지막으로 다들 아시겠지만 지역변수는 초기화가 반드시 필요합니다. 그리고 메서드 내에서만 존재하고 메서드가 실행될 때 메모리에 올라갔다가 메서드 종료 때 메모리에서 사라져 버립니다.
두 메서드에서 int x는 제각기 다른 존재입니다. 그리고 지역변수는 초기화 없이 사용할 수 없습니다.
지역변수를 초기화하지 않으면 에러가 발생합니다. 지역변수를 반드시 초기화해줘야 하는 이유는 지역변수는 메서드 내에서 계산을 위해 쓰일 목적으로 만들어지는데 초기화되어 있지 않으면 메서드를 실행 시 예기치 않은 값이 될 수 있기 때문입니다. 그래서 컴파일러가 이러한 상황이 발생하는 것을 피하기 위해 프로그래머에게 초기화할 것을 요청하게 됩니다. 변수를 선언하고 처음으로 값을 저장하는 것을 변수 초기화 라고 한다. 변수의 초기화는 경우에 따라 필수적일수도 선택적일수도 있지만 가능하면 선언과 동시에 적절한 값으로 초기화하는 것이 바람직하다. 멤버변수는 초기화를 하지 않아도 변수의 타입에 맞는 기본값으로 초기화가 이루어지지만 지역변수는 사용하기 전에 반드시 초기화가 이루어져야 한다.
각 타입의 기본값(default value)자료형기본값 8false 9'\u0000' 0, 1, 20 30 40.0f 50.0d or 0.0renference valuenull멤버변수를 초기화하는 방법은 다음과 같다.
2. 명시적 초기화변수 선언과 동시에 초기화 하는 것을 명시적 초기화(explicit initialization), 변수의 초기화라고 한다. 가장 기본적이면서도 간단한 초기화 방법이므로 여러 초기화 방법 중에서도 가장 우선적으로 고려되어야 한다.
3. 초기화 블럭초기화 블럭의 종류에 따라 정리하면 다음과 같다.
초기화 블럭 내에는 메서드 내에서와 같이 조건문, 반복문, 예외처리구문 등을 자유롭게 사용할 수 있으므로, 초기화 작업이 복잡하여 명시적 초기화만으로는 부족한 경우 초기화 블럭을 사용한다.
인스턴스 변수의 초기화는 주로 생성자를 사용하고, 인스턴스 초기화 블럭은 모든 생성자에서 공통으로 수행되야 하는 코드를 넣는데 사용 한다. 아래와 같이 모든 생성자에서 공통으로 수행되어야 하는 문장들이 있을 때, 이 문장들을 각 생성자마다 써주기보다는 인스턴스 블럭에 넣어줌으로써 코드가 보다 간결하게 작성할 수 있다.
초기화 블럭 예제 1 : 초기화 순서예제를 통해 초기화 순서가 어떻게 진행되는지 보자.
콘솔화면에서와 같이 클래스 초기화 블럭, 인스턴스 블럭, 생성자 순으로 초기화가 진행된다. 초기화 블럭의 경우 메모리에 로딩될 때 한번만 초기화가 이루어지고, 인스턴스 블럭과 생성자는 인스턴스가 생성될 때마다 초기화가 수행된다. 초기화 블럭 예제 2 : Car() {
count++; // 코드 중복
serialNo = count; // 코드 중복
color = "white";
gearType = "auto";
}
Car(String color, String gearType) {
count++; // 코드 중복
serialNo = count; // 코드 중복
this.color = color;
this.gearType = gearType;
}
|