코린이의 소소한 공부노트

선언 위치에 따른 변수의 종류 본문

Java

선언 위치에 따른 변수의 종류

무지맘 2022. 3. 3. 00:34

변수는 타입으로도 종류가 나눠지지만, 선언된 위치에 따라서도 종류가 나뉜다. 아래 나온 코드가 이 글의 요약본이다.

class Variables{ // 클래스 영역 시작

	int iv; // 인스턴스 변수
	static int cv; // 클래스 변수

	void method() { // 메서드 영역 시작
		int lv1; // 지역변수
	}// 메서드 영역 끝
    
}// 클래스 영역 끝

 

코드에는 2가지 영역이 존재한다.

1. 클래스 영역

  - 클래스의 이름으로 시작해 중괄호{ }로 감싸고 있는 영역

  - 변수 생성 가능(클래스 변수, 인스턴스 변수) -> 필드/멤버 변수/전역 변수로도 불림

  - 메서드 선언(메서드의 이름만 적는 것) 가능

  - 메서드 정의(메서드 내부까지 구현한 것) 가능

  - 변수/메서드 선언 시 선언문의 순서는 상관없지만, 보통 변수를 선언 후 메서드 선언을 함

2. 메서드 영역

  - 메서드의 이름으로 시작해 중괄호{ }로 감싸고 있는 영역

  - 변수 생성 가능(지역 변수)

  - 다른 메서드 호출 가능

  - 클래스 내부에 선언함

  - 가장 유명한 메서드는 메인 메서드 -> public static void main(String args[]) { // 생략 }

 

이 2가지 영역 중 어디에 어떤 식으로 선언이 되냐에 따라 3가지 변수로 나뉘게 된다.

1. 클래스 변수(class variable, cv)

  - static + iv (스태틱변수, 공유변수)

  - 클래스 영역에 생성된 변수

  - 유효범위: 클래스 영역 전체(메서드 영역 포함)

  - 클래스가 메모리에 올라갈 때 생성됨 -> CPU는 RAM(메모리)에 올린 내용만 읽을 수 있어 프로그램을 실행시키려면 HDD(하드디스크)에서 메모리로 파일들을 로딩(loading)해야 한다. 이때 클래스 변수가 생성된다. 즉, 객체 생성을 하지 않아도 클래스 변수는 생성된다.

  - 프로그램 종료 시 제거됨

2. 인스턴스 변수(instance variable, iv)

  - 클래스 영역에 생성된 변수

  - 유효범위: 클래스 영역 전체(메서드 영역 포함)

  - 인스턴스(객체)가 생성될 때 생성됨

  - 객체를 참조하는 변수가 없어지면 가비지 콜렉터에 의해 제거됨

3. 지역 변수(local variable, lv)

  - 메서드 내부에 생성된 변수

  - 유효범위: 메서드 영역 내

  - 메서드 내에서 선언문이 수행될 때 생성됨

  - 메서드 종료 시 자동 제거

 

지역변수는 많이 써봤으니, 클래스 변수와 인스턴스 변수의 차이를 예시를 들어 설명하겠다.

트럼프 카드는 스페이드, 다이아몬드, 하트, 클로버의 4개의 무늬와 A, 2, 3, ..., 10, J, Q, K까지 13개의 숫자의 조합으로 구성되어있다. 중복되는 카드가 없다고 한다면 무늬와 숫자는 각 카드마다 다를 것이고, 카드의 크기는 모두 같을 것이다.

이것을 Card 클래스의 속성으로 나타내 보자.

1) 무늬/숫자

  - 각 카드마다 다른 값이다.

  - 이는 iv로 나타낸다.

2) 크기

  - 폭과 높이로 나눠서 나타낸다.

  - 모든 카드가 공통으로 갖고 있는 값이다.

  - 이는 cv로 나타낸다.

이를 클래스로 나타내면 다음과 같다.

class Card{
    // iv
    String pattern; // 무늬
    int number; // 숫자 (A=1, J=11, Q=12, K=13)
    
    // cv
    static int width = 100; // 폭
    static int height = 250; // 높이
}

Card 클래스를 이용해서 메인 메서드에서 객체 2개를 생성해 보겠다. 

// 스페이드 9
Card c1 = new Card(); // iv 생성
c1.pattern = "SPADE";
c1.number = 9;

// 다이아 4
Card c2 = new Card(); // iv 생성
c2.pattern = "DIAMOND";
c2.number = 4;

해당 프로그램을 실행시킬 때 cv인 width와 height는 메모리상에 공간이 생기고 각각 100과 250이 저장된다. iv인 pattern과 number는 각 객체(c1, c2)가 생성될 때 함께 생긴다.

객체 생성까지 했으니 한번 사용해보겠다. 먼저, 각 Card 객체의 iv를 출력해보자.

System.out.println("c1은 " + c1.pattern + " " + c1.number);
System.out.println("c2는 " + c2.pattern + " " + c2.number);
// "c1은 SPADE 9"
// "c2는 DIAMOND 4"

아주 잘 나오는 것을 확인할 수 있다. 이렇게 보면 객체는 iv를 묶어놓은 것이라고 볼 수도 있겠다.

그럼 이제 cv를 출력해보자.

System.out.println("c1의 크기는 " + Card.width + " * " + Card.height);
System.out.println("c2의 크기는 " + Card.width + " * " + Card.height);

// "c1의 크기는 100 * 250"
// "c2의 크기는 100 * 250"

cv는 클래스이름.변수이름으로 접근하는 것이 좋다. 이름 그대로 클래스 변수이기 때문이다. 물론,

System.out.println("c1의 크기는 " + c1.width + " * " + c1.height);
System.out.println("c2의 크기는 " + c2.width + " * " + c2.height);

// "c1의 크기는 100 * 250"
// "c2의 크기는 100 * 250"

이렇게 객체 이름을 넣어서 해도 결과는 똑같다. 같은 클래스의 객체는 클래스 변수를 공유하기 때문이다. 하지만 위의 방법은 권장하지 않는다. iv와 cv를 확실히 구분 짓기 위해 cv는 클래스 이름을 써서 접근하도록 하자.

여기서 궁금증을 하나 풀고 가자. cv는 정말 각 객체가 공유할까?

// 객체 c1으로 cv에 접근해 값 변경
c1.width = 200;
c1.height = 100;

System.out.println("c1의 크기는 " + c1.width + " * " + c1.height);
System.out.println("c2의 크기는 " + c2.width + " * " + c2.height);

// "c1의 크기는 200 * 100"
// "c2의 크기는 200 * 100"

c1으로 cv에 접근해서 값을 바꿨는데, c2까지 바뀐 것을 확인할 수 있다. cv를 실시간으로 공유하고 있음을 알 수 있다.

그럼 여기서 궁금증 하나 더, cv값이 변경된 상태에서 새 Card 객체를 생성하면 그 객체의 크기는 어떻게 나올까?

Card c3 = new Card();
System.out.println(c3.width + " * " + c3.height);
// 200 * 100

변경된 값으로 나오는 것을 확인할 수 있다. 

클래스 영역의 변수를 이용할 때, iv는 객체이름.변수이름으로, cv는 클래스이름.변수이름으로 쓰는 것을 잊지 말자.

'Java' 카테고리의 다른 글

메서드의 호출 스택  (0) 2022.03.05
메서드의 생성(선언)과 사용(호출)  (0) 2022.03.04
클래스의 정의  (0) 2022.03.02
객체 배열  (0) 2022.03.01
클래스, 객체, 인스턴스  (0) 2022.02.20