본문 바로가기

코딩 국비 학원/Do it! 자바 프로그래밍 입문

[Do it! 자바 프로그래밍 입문]this 예약어, 객체 간 협력, static 변수

22.12.10 배운 내용 정리
(this 예약어, 객체 간 협력, static 변수)

 

this 예약어

 

this = 생성된 인스턴스 스스로를 가리키는 예약어

 

 

※ 인스턴스가 생성된 동적 메모리(힙) 주소는 실제 주소가 아닌 자바 가상 머신이 생성한 주소임

 

참조 변수 = 인스턴스를 가리키는 변수

참조 변수를 출력하면 '클래스 이름@메모리 주소' 문자열 값이 나옴

오른쪽 출력값을 보면 bDay.printThis() 메서드를 호출하여 출력한 this 값이 참조 변수 bDay를 출력한 값과 같음.

즉 클래스 코드에서 사용하는 this는 생성된 인스턴스 자신을 가리키는 역할을 함.

따라서 this.year = year; 문장으로 참조하면 동적 메모리에 생성된 인스턴스의 year 변수 위치를 가리키고

그 위치에 매개변수 값을 넣어주는 것임.

 

※ 하나의 파일에 여러 개의 클래스 존재 가능

하나의 자바 파일에 하나의 클래스가 있는 경우가 대부분이지만

하나의 파일에 여러 개의 클래스가 존재할 수도 있음.

이때 public 클래스는 하나뿐이며 public 클래스와 자바 파일 이름은 같아야함.

 

생성자에서 다른 생성자를 호출하는 this

 

this를 사용해 클래스의 생성자에서 다른 생성자를 호출할 수 있음.

 

 

Person 클래스에는 Person( ) 디폴트 생성자와 매개변수를 가지는 Person(String, int) 생성자가 있음.

클래스가 생성될 때 Person(String, int)가 호출죄어 이름과 나이를 전달받고,

Person( ) 디폴트 생성자가 호출되는 경우에는 초킷값으로 "이름 없음"과 1값을 대입하고자 함.

 

※ this로 다른 생성자를 호출할 때 주의할 점

this를 사용하여 생성자를 호출하는 코드 이전에 다른 코드를 넣을 수 없음.

생성자는 클래스가 생성될 때 호출되므로 클래스 생성이 완료되지 않은 시점에 다른 코드가 있다면 오류 발생 가능.

즉 디폴트 생성자에서 생성이 완료되는 것이 아니라 this를 사용해 다른 생성자를 호출하므로,

이때는 this를 활용한 문장이 가장 먼저 와야 함.

 

자신의 주소를 반환하는 this

 

this를 사용하여 생성된 클래스 자신의 주소 값을 반환할 수 있음.

인스턴스 주소 값을 반환할 때는 this를 사용하고 반환형은 클래스 자료형을 사용함.

 

 


 

객체 간 협력

 

객체 지향 프로그램은 객체를 정의하고 객체 간 협력으로 만듦

ex. 학생이 학교에 가기 위해 수행하는 여러 과정을 객체 지향 프로그램으로 만들 수 있고,

여러 객체의 협력이 이루어지는 과정을 프로그램으로 구현 가능 함.

학생이 버스나 지하철을 타고 학교에 가는 것을 객체 지향으로 프로그래밍 하는 경우

→ 학생, 버스, 지하철 세 객체를 만들고 이들 사이에 어떻게 협력이 이루어지는지 살펴보기

 

학생 클래스 구현

 

학생 클래스는 '이름', '학년', '가진 돈'을 멤버 변수(속성)로 가지며,

'버스를 탄다', '지하철을 탄다', '학생의 현재 정보를 보여준다'를  메서드(멤버 함수)로 가짐.

 

학생 클래스 구현

 

★ 해당 코드를 작성할 때 13, 17행에서 Bus & Subway cannot be resolved to a type라는 오류가 발생하는데

이 뒤에 버스와 지하철 클래스 구현까지 완료하면 오류는 해결된다.

 

8행에 생성자는 학생 이름과 학생이 가진 돈을 매개변수로 받으며,

학생 클래스를 하나 생성하면 학생 이름과 학생이 가진 돈을 초기화 함.

디폴트 생성자 제공 X, 따라서 학생 클래스를 생성하기 위해선

매개변수가 있는 Student(String studentName, int money) 생성자를 호출 해야함.

takeBus( ) 메서드는 학생이 한 버스를 선택해서 탄 경우를 구현한 코드이며

버스를 타면 버스 요금(1,000)원을 내기 때문에 this -= 1000; 문장이 수행되면

학생이 가진 돈이 1,000원 줄어듦. (지하철도 마찬가지)

그리고 마지막 showInfo( ) 함수는 학생 정보를 출력해 줌.

 

버스 클래스 구현

 

버스 객체 = 학생 한 명이 승차하면 버스 요금을 받고 승객 수가 증가함

 

버스 클래스 구현

 

버스 클래스의 멤버 변수로는 버스 번호, 승객 수, 버스가 받은 요금 총액이 있음

take( ) 메서드에서 승객 한 명이 버스를 탄 경우를 구현해보면, 승객이 요금을 지불하기 때문에

요금을 매개변수로 받고(거스름돈 생략), 요금이 들어오면 버스 수입과 승객 수가 증가함.

Bus(int busNumber) 생성자에서는 버스 번호를 매개변수로 받아 버스가 생성될 때 버스 번호를 초기화 함.

showInfo( ) 메서드에서는 버스 번호와 버스를 탄 승객 수, 버스 수입을 문자열로 연결하여 출력함.

 

지하철 클래스 구현

 

위의 버스 클래스 구현과 유사함.

 

지하철 클래스 구현

 

학생, 버스, 지하철, 객체 협력

 

※ 지금까지 구현한 Student, Bus, Subway 클래스를 기반으로 학생이 버스나 지하철을 탔을 때의 상황 구현하기

ex. 두 학생 James와 Tomas가 있고, 이 두 학생은 각각 버스와 지하철을 한 번씩 타고 학교에 간다고 했을 때

두 학생이 교통 수단을 이용한 후 각자가 가진 돈의 변화와 버스, 지하철 수입의 합을 알아보기

 

 

객체 간 협력은 학생, 버스, 지하철 사이에 이루어짐.

학생은 버스나 지하철을 이용할 수 있고,

학생이 버스를 선택하면 학생이 가진 돈은 1,000원이 줄고, 버스 승객이 1명 증가하고, 버스 수입은 1,000원 증가함.

학생이 지하철을 선택하면 가진 돈은 1,500원이 줄고, 지하철 승객이 1명 증가하고, 지하철 수입은 1,500원 증가함. 

이렇게 객체를 클래스로 만들어 구현하면 객체 사이에는 서로 어떤 값을 주고받고 메서드를 호출하는 일이 발생함.

 


 

변수를 여러 클래스에서 공통으로 사용하기 위한 방법

 

ex. 학생 클래스를 사용하면 여러 학생의 인스턴스를 만들 수 있음.

public class Student {

  public int studentID;

  public String studentName;

  public int grade;

  public String address;

}

 

학생마다 고유한 학번(studentID)을 가지며, 학생이 입학하면(클래스가 생성되면) 학번이 자동으로 생성되고,

생성된 인스턴스는 학번을 순서대로 가져야 할 때 학생에게 학번을 부여할 수 있는 방법

→ 각 인스턴스마다 따로 생성되는 변수가 아닌, 클래스 전반에서 공통으로 사용할 수 있는 기준 변수가 있어야 하고,

학생이 한 명 생성될 때마다 기준 변수 값을 하나씩 증가시켜 각 학생 인스턴스의 학번 변수에 대입해 주면 됨.

이 때 클래스에서 공통으로 사용하는 변수를 'static 변수'로 선언함.

 

static 변수의 정의와 사용 방법

 

static 변수 = '정적 변수'라고도 하며, 자바 뿐만아니라 다른 언어에서도 비슷한 개념으로 사용하고 있는 변수로서

자바에서는 다른 멤버 변수처럼 클래스 내부에 선언하며, 변수를 선언할 때 자료형 앞에 static 예약어를 사용함

ex. static int serialNum;    //static 예약어/자료형/변수 이름

 

static 변수는 클래스 내부에 선언하지만, 다른 멤버 변수처럼 인스턴스가 생성될 때마다 새로 생성되는 변수가 아님.

static 변수는 프로그램이 실행되어 메모리에 올라갔을 때 딱 한 번 메모리 공간이 할당되며,

그 값은 모든 인스턴스가 공유함. 즉 static으로 선언한 변수는 인스턴스 생성과 상관없이 먼저 생성되고

그 값을 모든 인스턴스가 공유하게 되는 것임.

이러한 이유 때문에 static 변수를 클래스에 기반한 변수라고 해서 '클래스 변수'라고도 함.

 

※ static 변수 사용 방법

ex.학생이 새로 생성되면 학번을 차례로 부여하는 예제에서 사용할 static 변수는 serialNum임.

변수의 값은 학생이 생성될 때마다 순서대로 증가되며,

이 증가된 값을 각 학생의 학번에 대입해주면 학생에게 새로운 학번이 부여됨

 

 

※ 테스트 코드에서 학생을 두 명 생성하고 serialNum이 증가했을 때 두 인스턴스에서 증가된 값이 공유되는지 확인

 

 

★ 왼쪽의 경우 오류가 아니고 static 변수이므로 인스턴스 참조 변수가 아닌 클래스 이름으로 직접 참조하라는 뜻임.

오른쪽 처럼 클래스 이름으로 (ex. studentLee → Student) 직접 참조해주면 오류는 사라짐.

추가로 이클립스에서 static 변수와 static 메서드는 이탤릭체로 나타남.

 

static으로 선언한 serialNum 변수는 모든 인스턴스가 공유하기 때문에 studentLee & Son 으로 serialNum 변수 값을 출력해 보면 둘 다 1001로 증가되어 출력됨. 즉 두 개의 참조 변수가 동일한 변수의 메모리를 가리키고 있다는 것을 알 수 있음.

 

※ 학번 자동 부여 프로그램 구현

학생이 한 명 생성될 때마다 학번을 자동으로 부여하는 프로그램 구현

 

 

주의할 점 : static 변수를 그냥 바로 학번으로 사용하면 안됨!!

그 이유는 static 변수는 모든 인스턴스가 공유하는 변수이므로 이 변수를 바로 학번으로 사용하면

모든 학생이 동일한 학번 값을 가지게 되기 때문.

학번은 학생의 고유 번호이므로 학생의 멤버 변수로 선언해 주고, 학생이 한 명 생성될 때마다

증가한 serialNum 값을 studentID에 대입해 주면 문제 해결 가능.

Student 클래스에 생성자를 추가하고 생성자에서 serialNum 값을 증가시키고 증가된 값을 studentID 변수에 대입함.

 

※ 실제로 학생이 생성될 때마다 증가된 다른 학번을 가지는지 확인

 

 

학생 인스턴스를 생성할 때마다 serialNum 변수 값이 증가하고,

새로 생성되는 학생마다 가지는 studentID 변수에 증가한 serialNum 값을 복사해 주었으므로, 두 학생의 학번은 다름.

이처럼 static 변수는 같은 클래스에서 생성된 인스턴스들이 같은 값을 공유할 수 있으므로,

인스턴스 간에 공통으로 사용할 값이 필요한 경우 유용하게 사용가능

 

클래스 변수

 

static 변수는 인스턴스를 생성할 때마다 만들어지는 것이 아니고 클래스를 선언할 때

특정 메모리에 저장되어 모든 인스턴스가 공유하는 변수이며,

인스턴스 생성과는 별개이기때문에 인스턴스보다 먼저 생성됨.

그러므로 인스턴스가 아닌 클래스 이름으로도 참조하여 사용가능함.

따라서 자바에서는 static 변수를 클래스 변수라고도 하는데 그 이유는 인스턴스마다 생성되는 변수가 아니라

클래스에 속해 한 번만 생성되는 변수이고 이를 여러 인스턴스가 공유하기 때임.

 

 

클래스 이름으로 static 변수 참조

 

보통 static 변수는 인스턴스 참조 변수가 아닌 클래스 이름으로 직접 참조함.

 

클래스 메서드

 

클래스 메서드= static 메서드

ex. serialNum 변수를 사용하는 메서드를 만들 때, 외부 클래스에서 serialNum 변수를 직접 참조하지 못하도록

private으로 선언하고 이 변수에 대한 get( ) 메서드와 set( ) 메서드를 생성함.

그리고 Student 클래스의 serialNum 변수를 private으로 변경하면

기존의 StudentTest1,2,3에서는 직접 참조가 불가능해 오류가 발생하므로 클래스를 새로 생성해야함.

 

 

이제 외부 클래스에서 serialNum 값을 사용하려면 get( ) 메서드를 호출하고,

serialNum 변수 값을 변경하려면 set( ) 메서드를 사용해야함.

 

※ get( ), set( ) 메서드 활용 학번 출력

 

 

클래스 메서드와 인스턴스 변수

 

클래스 메서드 내부에서는 인스턴스 변수를 사용할 수 없음.

 

오류 발생

 

getSerialNum( ) 메서드 = static 예약어를 붙인 클래스 메서드로 세 종류의 변수를 사용하고 있음.

가장 먼저 선언한 int i를 보면 이 변수는 메서드 내부에서 선언했는데 이렇게 메서드 내부에서 선언한 변수를

그 지역에서만 사용한다고 해서 '지역 변수'라고 함.

지역 변수메서드가 호출될 때 메모리에 생성되어 메서드가 끝나면 사라지는 변수로,

즉 이 변수는 getSerialNum( ) 메서드 내부에서만 사용가능함.

마지막 return serialNum; 문장을 보면 serialNum 변수는 static 변수임.

그러므로 클래스 메서드인 getSerialNum( ) 메서드 내부에서도 사용 가능함.

 

but 메서드 내부의(25행) studentName 변수는 오류가 발생함.

이 변수는 student2 클래스의 멤버 변수로, 인스턴스가 생성될 때 만들어지는 인스턴스 변수이기 때문

 

※ 클래스 메서드와 클래스 변수는 인스턴스가 생성되지 않아도 사용 가능

 

 

클래스 메서드 내부에서 지역 변수와 클래스 변수는 사용할 수 있지만, 인스턴스 변수는 사용할 수 없음.

또한 클래스 메서드에서 인스턴스 변수를 사용할 수는 없지만,

반대로 일반 메서드에서 클래스 변수를 사용하는 것은 문제 없음.

그 이유는 일반 메서드는 인스턴스가 생성될 때 호출되는 메서드이고,

클래스 변수는 이미 만들어진 변수이기 때문에 일반 메서드에서도 클래스 변수를 호출할 수 있기 때문.