지난 글: [프로그래밍 언어/JAVA] - JAVA 입문 - 객체 간 협력
변수를 여러 클래스에서 공통으로 사용하려면
지난 글에서 만든 학생 클래스를 떠올려보자.
학생 클래스를 사용하면 여러 학생의 인스턴스를 만들 수 있다.
그리고 학생마다 고유한 학번(studentID)를 갖는다.
여기서 학생 클래스가 생성될 때 학번이 자동으로 생성되도록 하려면 어떻게 해야할까.
생성된 인스턴스는 학번을 순서대로 가져야 한다. 이 경우에 각 인스턴스마다 따로 생성되는 변수가 아닌,
클래스 전반에서 공통으로 사용할 수 있는 기준 변수가 있어야한다.
그리고 학생이 한 명 생성될 때마다 기준 변수 값을 하나씩 증가시켜 각 학생 인스턴스의 학번 변수에 대입해주면 된다.
이 때 클래스에서 공통으로 사용하는 변수를 'static 변수'로 선언한다.
static 변수의 정의와 사용 방법
static 변수란 다른 용어로 '정적 변수'라 한다. static 변수는 자바뿐만 아니라 다른 언어에서도 비슷한 개념으로
사용하고 있는 변수이며 JAVA에서는 다른 멤버 변수처럼 클래스 내부에 선언한다.
변수를 선언할 때 다음과 같이 자료형 앞에 static 예약어를 사용한다.

static 변수는 클래스 내부에 선언하지만, 다른 멤버 변수처럼 인스턴스가 생성될 때마다 새로 생성되는 변수가 아니다.
static 변수는 프로그램이 실행되어 메모리에 올라갔을 때 딱 한 번 메모리 공간이 할당된다.
그리고 그 값은 모든 인스턴스가 공유한다.
즉 일반 멤버 변수는 인스턴스가 생성될 때마다 새로 생성되어 각각 다른 값을 가지게 되지만, static으로 선언한 변수는
인스턴스 생성과 상관 없이 먼저 생성되고 그 값을 모든 인스턴스가 공유하는 것이다.
이 때문에 static 변수를 클래스에 기반한 변수라고 해서 '클래스 변수'라고도 한다.
이제 학생이 새로 생성되면 학번을 차례로 부여하는 프로그램을 구현해보자.

Student 클래스에서 기준 값 역할을 하는 serialNum 변수를 선언하고 기준 값으로 1000을 대입한다.
다음의 테스트 코드에서 학생을 두 명 생성하고 serialNum이 증가할 때 두 인스턴스에서 증가된 값이 공유되는지 보자.


studentChoi를 먼저 생성하고 이 참조 변수를 사용하여 전체 인스턴스에서 공통으로 사용하는
serialNum 변수 값을 1 증가시킨다.
그리고 studentKim을 생성하고 아무런 연산도 수행하지 않는다.
그 다음에 studentKim과 studentChoi로 serialNum 변수 값을 출력해 보면 둘 다 1001로 증가된 serialNum 값이
출력되는 것이 보인다.
static으로 선언한 serialNum 변수는 모든 인스턴스가 공유하기에 두 개의 참조 변수가 동일한 변수의 메모리를
가리키고 있다는 것을 알 수 있다.
학번 생성하기
이제 원래 구현하려 했던 학생이 한 명 생성될 때마다 학번을 자동으로 부여하는 프로그램을 완성해보자.

static 변수(serialNum)를 하나 선언한다.
학생이 생성될 때마다 이 변수 값이 증가한다.
여기서 주의할 점은 static 변수를 그냥 바로 학번으로 사용하면 안된다.
이유는 static 변수는 모든 인스턴스가 공유하는 변수이므로 이 변수를 바로 학번으로 사용하면 모든 학생이
동일한 학번 값을 갖게 되기 때문이다.
학번은 학생의 고유 번호이므로 학생의 멤버 변수로 선언하고, 학생이 한 명 생성될 때마다 증가한 serialNum의 값을
studentID에 대입하면 된다.
Student1 클래스에 생성자를 추가하고 생성자에서 serialNum 값을 증가시키고 증가된 값을 studentID 변수에 대입한다.
그럼 이제 StudentTest2 클래스를 만들어 실제로 학생이 생성될 때마다 증가된 다른 학번을 갖는지 확인해보자.


학생 인스턴스를 생성할 때마다 serialNum 변수의 값은 증가한다.
그리고 새로 생성되는 학생마다 갖는 studentID 변수에 증가한 serialNum 값을 복사해 주었으므로,
두 학생의 학번은 다르다.
이처럼 static 변수는 같은 클래스에서 생성된 인스턴스들이 같은 값을 공유할 수 있으므로,
인스턴스 간에 공통으로 사용할 값이 필요한 경우 유용하게 사용할 수 있다.
클래스 변수
위에서 봤들이 static 변수는 인스턴스를 생성할 때마다 만들어지는게 아니고 클래스를 선언할 때 특정 메모리에
저장되어 모든 인스턴스가 공유하는 변수이다.
static 변수는 인스턴스 생성과는 별개이므로 인스턴스보다 먼저 생성된다.
그러므로 인스턴스가 아닌 클래스 이름으로도 참조하여 사용할 수 있다.
따라서 JAVA에서는 static 변수를 클래스 변수라고도 하며, StudentTest2 코드를 다음처럼 변경할 수 있다.


StudentTest2.Java 파일처럼 static 변수 serialNum을 studentChoi.serialNum과 같이 인스턴스로 참조할 수도 있다.
하지만 static 변수는 인스턴스가 생성되지 않아도 사용할 수 있기에 보통은 Student.serialNum과 같이
클래스 이름과 함께 사용한다.
지금까지 static 변수, 정적 변수, 클래스 변수라는 세 가지 용어를 배웠다.
셋 모두 JAVA에서는 static 변수를 의미한다.
JAVA에서 static 변수를 클래스 변수라고 하는 이유는 클래스에 속해 한 번만 생성되는 변수이고 이를
여러 인스턴스가 공유하기 때문이다.
클래스 메서드
일반 멤버 변수를 위한 메서드가 존재하듯이 static 변수를 위한 메서드도 있다.
이런 메서드를 'static 메서드' 또는 '클래스 메서드'라고 한다.
위의 serialNum 변수를 사용하는 메서드를 만들어보자.
외부 클래스에서 serialNum 변수를 직접 참조하지 못하도록 private으로 선언하고 이 변수에 대한
get( ), set( ) 메서드를 생성한다. Student클래스의 serialNum 변수를 private으로 변경하면 기존의 StudentTest1,
StudentTest2에서는 직접 참조할 수 없어 오류가 발생하므로 Student2 클래스를 새로 생성한다.

이제 외부 클래스에서 serialNum 값을 사용하려면 get( ) 메서드를 호출하고, serialNum 변수 값을 변경하려면
set( ) 메서드를 사용해야 한다.
get( ) 메서드와 set( ) 메서드를 사용하도록 변경했을 때 프로그램이 제대로 실행되는지 확인해보자.


StudentTest4.java의 7행과 12행 코드는 serialNum을 직접 참조하지 않고 getSerialNum( ) 메서드를 호출하여 참조한다.
static 변수처럼 인스턴스 참조 변수가 아닌 클래스 이름으로 직접 호출할 수 있다.
클래스 메서드와 인스턴스 변수
클래스 메서드 내부에서는 인스턴스 변수를 사용할 수 없다.


getSerialNum( ) 메서드는 static 예약어를 붙인 클래스 메서드이다.
이 메서드는 세 종류의 변수를 사용하고 있다. 우선 가장 먼저 선언한 int i를 보자.
이 변수는 메서드 내에서 선언하였다. 이렇게 메서드 내부에서 선언한 변수를 그 지역에서만 사용한다 해서
지역 변수라고 한다. 지역 변수는 메서드가 호출될 때 메모리에 생성되어 메서드가 끝나면 사라지는 변수이다.
따라서 이 변수는 getSerialNum( ) 메서드 내부에서만 사용할 수 있다.
마지막 return serialNum; 문장을 보면 serialNum 변수는 static 변수이다.
그러므로 클래스 메서드인 getSerialNum( ) 메서드 내부에서도 사용할 수 있다.
하지만 메서드 내부의 두 번째 줄에 사용한 studentName 변수는 오류가 생긴다.
이 변수는 Student2 클래스의 멤버 변수로, 인스턴스가 생성될 때 만들어지는 인스턴스 변수이기 때문이다.
클래스 메서드와 클래스 변수는 인스턴스가 생성되지 않아도 사용할 수 있다.
다음 사진을 보자.


5행을 보면 클래스 메서드는 Student2.getSerialNum( ) 과 같이 인스턴스가 생성되지 않아도 언제든 호출할 수 있다.
따라서 studentName처럼 인스턴스가 생성되어야 메모리가 할당되는 인스턴스 변수는 클래스 메서드에서
사용할 수 없다.
참고 서적: 자바 프로그래밍 입문 - 박은종
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
JAVA 입문 - 싱글톤 패턴 (0) | 2022.05.14 |
---|---|
JAVA 입문 - 변수 유효 범위 (0) | 2022.05.14 |
JAVA 입문 - 객체 간 협력 (0) | 2022.05.12 |
JAVA 입문 - this 예약어 (0) | 2022.05.11 |
JAVA 입문 - 정보 은닉 (0) | 2022.05.10 |