변수의 초기화, 멤버 변수의 초기화
변수의 초기화
- 지역변수(lv)는 수동 초기화 해야함 (사용전 꼭!!)
- 멤버변수(iv, cv)는 자동 초기화된다.
코드가 있을 때,
x와 y는 iv이고,
i와 j는 메서드 안에 선언되어있으므로 lv이다.
지역변수 i를 선언하고, i를 j에 넣는데 에러가 난다.
왜냐하면, i값이 뭔지 모르기 때문이다. 근데 그 모르는 값 i를 j에 넣으려고 하니까 에러가 발생한다.
이게 왜 값을 모르냐면, 호출스택을 살펴보면 알 수 있다.
호출스택은 재사용이 빈번한 메모리다. 아주 짧은 시간동안 같은 메모리 공간을 다른 메서드가 썻다가 지웠다가를 하는 것이다.
그런데 메서드가 호출될 때마다 이 메모리 공간을 0으로 초기화 하면, 성능이 떨어진다.
그래서 성능을 높히려고 항상 0으로 초기화 하지 않고, 새로운값으로 덮어쓰는 방식으로 초기화 한다.
지역변수는 메서드가 호출되서 작업하는 동안만 존재하기 때문에, 생명주기가 굉장히 짧다.
근데, 메서드는 빨리 실행되고 빨리 제거되야 하는데, 이것을 맨날 0으로 초기화했다가 쓰기에는 성능이 떨어진다.
그래서 새로운 값으로 덮어쓰는 방식으로 초기화 한다.
그래서 다른 메서드에서 사용하는 값이 뭔지는 모르지만 그값을 덮어쓰기 때문에,
위의 코드 i에서 그 값이 뭔지 모르는 것 이다.
그래서 lv는 꼭 수동 초기화를 해야한다.
그리고 iv나 cv는 자동초기화가 되는데, 객체는 여러 변수를 묶어 놓은 것이기 때문에 그변수를 전부다 0으로 초기화 하려면, 배열도 그렇고 자동초기화를 하지않으면 우리가 초기화해야하는 변수가 너무 많다. 그래서 자동으로 초기화를 해준다.
그리고, 자동초기화 되는 값은 어떤 값으로 초기화 되냐면, 타입마다 다르다.
타입에 따라서 기본값이 다르다. 대부분 0이고, 참조형같은 경우 null, boolean은 false이다.
타입마다 조금씩 다르긴 한데, 근본적으로는 0으로 초기화 된다.
멤버변수의 초기화
멤버변수를 초기화 하는 방법에는 여러가지가 있다. 하나씩 알아보자.
1. 명시적 초기화(=)
명시적초기화는 대입연산자를 이용해서 초기화 하는 것이다.
선언할 떄, 대입연산자를 사용하는 것이다.
iv를 대입연산자로 초기화 하는것이다. 이것을 명시적 초기화라고 한다.
변수를 선언한다음, 초기화 하는 가장 간단한 방법이다.
특히 참조형 변수의 초기화는, 객체를 만들어서 넣어줘야 한다. null값은 사실상 초기화가 아니다.
2. 초기화 블럭
- 인스턴스 초기화 블럭 : {}
- 클래스 초기화 블럭 : static {}
초기화 블럭은 복잡한 초기화에 사용한다.
{}안에다가 여러 문장을 넣을 수 있다.
여러 문장이 필요하면, 그리고 초기화를 하는데 복잡해지면, 초기화블럭이 필요하다.
초기화 블럭은 2개가 있는데,
iv를 초기화 할 때는, 인스턴스 초기화 블럭을 사용하고,
cv를 초기화 할 때는, 클래스 초기화 블럭을 사용한다.
3. 생성자
생성자도 초기화에 사용하는데, iv초기화, 복잡한 초기화에 사용한다.
정리를 해보면, 초기화가 3가지이다.
- 자동 초기화
- 간단 초기화
- 복잡 초기화
자동초기화는 우리가 안해줘도 0으로 자동으로 되는게 자동초기화,
간단 초기화는 대입연산자,
복잡초기화는 {}, static{}, 생성자 이렇게 3가지가 있다.
그런데 {}는 거의 사용하지 않고,
static{} 초기화는 cv초기화에 사용하고,
생성자는 iv초기화에 사용한다.
{}는 나중에 필요할 때 보면 된다.
아무튼, 정리해보면,
복잡한 초기화의 경우
cv를 초기화 할때는 static{}을 사용하면 되고,
iv를 초기화 할 때는 {}, 생성자를 사용하면 되는데 생성자를 주로 사용한다.
멤버변수의 초기화 - static {}
이번에는 static {}의 사용 예시를 한번 살펴보자.
arr int배열이 static이다. 즉, arr은 cv다.
이때, 내가 하고싶은 것은, arr배열을 난수를 만들어서 채워넣는것이다.
근데, 대입연산자로 할 수 있는 것은 배열 생성뿐이다.
난수를 채워넣는 것은, 명시적초기화(대입연산자)로는 할 수 가 없다.
그럼에도 불구하고, 명시적 초기화가 제일 먼저 고려되어야 한다.
간단히 할 수 있으면 간단히 하지, 괜히 대입 연산정도의 간단한 작업을 생성자나 static블럭같은곳에 넣을 필요가 없는 것이다.
그런데, 내가 하고싶은 작업을 대입연산자로 끝낼 수 없음을 확인했다.
그러면, 난수로 채우는 작업은 static블럭에서 한다. (static{}은 생략 가능)
cv복잡 초기화이다.
반복문을 이용해서 랜덤값을 배열의 각 요소에 집어넣는 것이다.
멤버 변수의 초기화 시점과 순서
클래스 변수 초기화 시점은, 클래스가 처음 로딩될 때 단 한번, 즉, 클래스가 메모리에 올라갈 때, 초기화 된다.
인스턴스 변수의 초기화 시점은, 인스턴스 객체가 만들어질때마다 초기화 된다.
코드를 보면, 명시적 초기화(간단 초기화),
static{} 과 생성자를 이용한 클래스 초기화, 인스턴스 초기화 (복잡 초기화) 가 있다.
먼저 IniTest it = new InitTest();의 객체를 만들면, 어떻게 될까?
먼저 클래스가 메모리에 올라간다. 즉 cv가 먼저 0으로 자동 초기화 된다.
그리고 명시적 초기화에 의해서 cv = 1이 된다. 이것은 대입연산자에 의한 간단초기화라 부른다.
그리고나서 복잡한 초기화 static{}에 의해서 cv 값이 2가 되었다.
여기까지하면 cv는 전부 초기화가 끝났다.
cv가 먼저 초기화 되고, iv가 초기화 된다.
iv는 처음에 0으로 자동초기화 되었다가,
명시적 초기화에 의해서 iv = 1이 되었다.(간단 초기화)
그리고 인스턴스 초기화 블럭이 실행되어 iv = 2로 바뀐다. (복잡 초기화)
그리고, 생성자에서 iv = 3이 된다.
이런식으로 쭉 순서대로 흘러가는 것이다.
그런데, 객체를 또 만들면 1, 2, 3 즉 클래스 초기화는 실행되지 않는다.
클래스 변수 초기화는 클래스가 처음 로딩될 때 단 한번 이루어지기 떄문이다.
초기화 순서
1. cv → iv
2. 자동(0) → 간단(=) → 복잡(static{}, 생성자)
'JAVA' 카테고리의 다른 글
클래스 간의 관계, 상속과 포함 (0) | 2022.03.30 |
---|---|
상속 (0) | 2022.03.30 |
생성자 this(), 참조변수 this (0) | 2022.03.29 |
생성자, 기본 생성자 (0) | 2022.03.29 |
오버로딩 (1) | 2022.03.28 |
댓글
이 글 공유하기
다른 글
-
클래스 간의 관계, 상속과 포함
클래스 간의 관계, 상속과 포함
2022.03.30 -
상속
상속
2022.03.30 -
생성자 this(), 참조변수 this
생성자 this(), 참조변수 this
2022.03.29 -
생성자, 기본 생성자
생성자, 기본 생성자
2022.03.29