변수의 초기화란 변수를 선언하고 값을 저장하는 것을 말한다. 보통은 선언과 동시에 초기화를 하지만 선언만 하고 초기화는 나중에 하는 경우도 있다.
멤버변수의 경우 선언만 할 경우 자료형에 맞는 기본값으로 초기화가 이루어지기 때문에 초기화없이 사용이 가능하다.
지역변수(메서드 내 있는 변수)는 반드시 사용하기 전 초기화가 필요하며 초기화하지 않고 사용할 경우 컴파일 에러가 발생한다.
class initialization{
int a; //인스턴스 변수
String b; //인스턴스 변수
void method1(){
int c; //지역변수
int d = c; //컴파일 에러. 초기화하지 않고 지역변수 사용
}
}
각 타입의 기본값
boolean : false
char : '\u0000'
byte, short, int : 0
long : 0L
float : 0.0f
double : 0.0d 또는 0.0
참조형 변수 : null
선언과 동시에 초기화하는 것을 명시적 초기화하고 한다. 가장 기본적이면서 간단한 초기화 방법으로 여러 초기화 방법 중에 가장 우선적으로 고려되야 한다.
class Book{
int price = 10000; //기본형 변수의 초기화
Page p = new Page(); //참조형 변수의 초기화
보다 복잡한 작업이 필요할 경우 초기화 블럭이나 생성자를 사용해야 한다.
초기화 블럭은 메서드처럼 조건문, 반복문, 예외처리구문 등을 사용할 수 있으며 초기화 작업이 복잡한 경우에 사용되고 클래스 초기화 블럭, 인스턴스 초기화 블럭으로 분류된다.
클래스 초기화 블럭 : 클래스 변수 초기화에 사용. 클래스가 메모리에 로딩될 때 한 번만 수행된다
인스턴스 초기화 블럭 : 인스턴스 변수 초기화에 사용. 인스턴스가 생성될 때마다 수행된다
class initialization{
static int cv;
int iv;
static{
// 클래스 초기화 블럭
}
{
// 인스턴스 초기화 블럭
}
}
초기화 블럭을 사용하지 않고 복잡한 초기화가 가능하지만 코드의 중복을 줄이고 재사용성을 높이기 위해 초기화 블럭을 사용하는 것이 효율적이며 객체지향적이다.
그렇다면 변수, 초기화 블럭, 생성자는 어느 순서대로 실행될까?
우선 클래스 변수의 초기화 시점은 클래스가 메모리에 로딩될 때 한 번 수행된다고 앞에서 언급하였다. 인스턴스 변수의 경우 인스턴스 생성 시 초기화 시점이 된다.
인스턴스 생성보다 메모리 로딩 시점이 더 앞서기 때문에 클래스 초기화가 인스턴스 초기화보다 먼저 수행된다.
클래스 변수 초기화 순서 : 기본값 -> 명시적 초기화 -> 클래스 초기화 블럭
인스턴스 변수 초기화 순서 : 기본값 -> 명시적 초기화 -> 인스턴스 초기화 블럭 -> 생성자
예제를 보면서 자세히 알아보자.
class initialization{
static int cv = 1; //명시적 초기화
int iv = 2; //명시적 초기화
static{cv = 2;
System.out.println("Static Initialization");
} //클래스 초기화 블럭
{iv = 3;
System.out.println("Instance Initialization");} //인스턴스 초기화 블럭
initialization(){
System.out.println("Constructor"); //생성자
}
}
우선, 클래스가 메모리에 로딩된 후 클래스 변수 cv는 명시적 초기화로 인해 1이다. 이후 클래스 초기화 블럭에 의해 2로 초기화되며 "Static Initialization"이라는 문구가 출력이 된다.
클래스 initialization의 인스턴스 생성 시 인스턴스 변수 iv의 명시적 초기화가 수행되어 2로 초기화 된다. 이후 인스턴스 초기화 블럭에 의해 3으로 초기화 되며 "Instance Initialization"이 출력된다.
마지막으로 생성자가 실행되어 "Constructor" 문구가 출력이 된다.
초기화 순서를 이용하여 제품 생산 시 일련번호를 부여하는 코드를 작성할 수 있다.
class Product{
static int num;
int serialnum;
{
++num;
serialnum = num;
}
Product(){
System.out.println("제품 일련번호" + serialnum);
}
}
public class ProductTest {
public static void main(String[] args) {
Product p1 = new Product();
Product p2 = new Product();
Product p3 = new Product();
Product p4 = new Product();
System.out.println("총 생산된 제품은 " + Product.num + "개입니다");
}
}
제품 일련번호1
제품 일련번호2
제품 일련번호3
제품 일련번호4
총 생산된 제품은 4개입니다
여기서 클래스 변수 num이 만약 인스턴스 변수였다면 인스턴스를 생성할 때마다 0으로 초기화 되었을 것이다. 클래스 변수이기 때문에 단 한 번만 초기화가 수행되며 인스턴스 초기화 블럭에서 인스턴스 생성할 때마다 num을 증가하게 구현하였기 때문에 제품의 개수 파악이 가능하다.
마지막으로 문서 번호 관련 예제를 만들어보자. 문서 저장 시 별도로 이름을 지정하지 않고 저장하면 임의로 문서 이름이 결정된다. 이를 생성자와 클래스 초기화 블럭을 이용하여 구현해보겠다.
class name{
static int num;
name(){
++num;
System.out.println("이름 없는 문서 " + num);} //문서 이름을 지정하지 않을 경우
name(String name){
System.out.println(name);} //문서 이름을 정할 경우
}
public class Document {
public static void main(String[] args) {
name n1 = new name();
name n2 = new name();
name n3 = new name();
name n4 = new name("자바는 어려워");
name n5 = new name();
}
}
기본 생성자는 문서 이름을 지정하지 않는 경우, String 매개변수가 있는 생성자는 문서 이름을 지정하는 경우로 하였다. 문서 이름을 지정하지 않으면(생성자에 매개변수를 넣지 않으면) 클래스 변수가 증가하여 문서 번호가 1씩 커지므로 규칙성 있는 문서 이름이 만들어진다.