2023. 1. 10. 21:00ㆍjava일지
2023/01/09
- 학습내용
1. this 예약어
1) 자신의 메모리를 가리키는 this
기본적으로 this는 생성된 인스턴스 스스로를 가리키는 예약어다.
class BirthDay {
int day;
int month;
int year;
public void setYear(int year) { //태어난 연도를 지정하는 메서드
this.year =year; //bDay.year = year;와 같은
}
public void printThis() { //this 출력 메서드
System.out.println(this); //System.out.println(bDay);와 같음
}
}
public class ThisExample {
public static void main(String[] args) {
BirthDay bDay = new BirthDay();
bDay.setYear(2000); //태어난 연도를 2000으로 지정
System.out.println(bDay); //참조 변수 출력
bDay.printThis(); //this 출력 메서드 호출
}
}
클래스 코드에서 사용하는 this는 생성된 인스턴스 자신을 가리키는 역할을 한다.
따라서 this.year = year; 문장을 참고해보면 동적 메모리에 생성된 인스턴스의 year 변수 위치를 가리키고 그 위치에 매개변수 값을 넣어 주는 것이다.
2) 생성자에서 다른 생성자를 호출하는 this
클래스에 생성자가 여러 개 있을 때 어떤 생성자에서 다른 생성자를 호출하는 경우가 있다.
이 때 this를 사용해 클래스의 생성자에서 다른 생성자를 호출할 수 있다.
class Person {
String name;
int age;
Person() {
this("이름 없음", 1); //this를 사용하여 Person(String, int) 생성자 호출
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
}
public class CallAnotherConst {
public static void main(String[] args) {
Person noName = new Person();
System.out.println(noName.name);
System.out.println(noName.age);
}
}
Person 클래스에는 Person() 디폴트 생성자와 매개변수를 가지는 Person(String, int) 생성자가 있다.
클래스가 생성될 때 Person(String, int)가 호출되어 이름과 나이를 전달받고,
Person() 디폴트 생성자가 호출되는 경우에는 초깃값으로 "이름 없음" 과 1 값을 대입한다.
3) 자신의 주소를 반환하는 this
this를 사용하여 생성된 클래스 자신의 주소 값을 반환할 수 있다.
인스턴스 주소 값을 반환할 때는 this를 사용하고 반환형은 클래스 자료형을 사용한다.
class Person {
String name;
int age;
Person() {
this("이름 없음", 1); //Person(String, int) 생성자 호출
}
Person(String name, int age) {
this.name = name;
this.age = age;
}
Person returnItSelf() { //반환형은 클래스형
return this;
}
}
public class CallAnotherConst {
public static void main(String[] args) {
Person noName = new Person();
System.out.println(noName.name);
System.out.println(noName.age);
Person p = noName.returnItSelf(); //this 값을 클래스 변수에 대입
System.out.println(p); //noName.returnItSelf()의 반환 값을 출력
System.out.println(noName); //참조 변수 출력
}
}
this를 반환하는 메서드를 사용할 일이 흔하지는 않지만,
클래스 자료형과 상관없이 클래스 내에서 this를 사용하면 자신의 주소 값을 반환할 수 있다.
2. 객체 간 협력
1) 학생 클래스 구현
public class Student {
public String studentName;
public int grade;
public int money;
public Student(String studentName, int money) {
this.studentName = studentName; //학생 이름과 가진 돈을 매개변수로 받는 생성자
this.money = money;
}
public void takeBus(Bus bus) {
bus.take(1000); //학생이 버스를 타면 1000원을 지불하는 기능을 구현한 메서드
this.money -= 1000;
}
public void takeSubway(Subway subway) {
subway.take(1500); //학생이 지하철을 타면1500원을 지불하는 기능을 구현한 메서드
this.money -= 1500;
}
public void showInfo() {
System.out.println(studentName+ "님의 남은 돈은" +money +"입니다.");
}
}
학생 클래스 멤버변수(속성): 학생이름, 학년, 돈
메서드(멤버 함수) : '버스를 탄다', '지하철을 탄다', '학생의 현재 정보를 보여준다.'
학생 클래스를 하나 생성하면 학생 이름과 돈을 초기화한다.
디폴트 생성자를 제공하지 않으므로 학생 클래스를 생성하려면 매개변수가 있는 Student(String studentName, int money) 생성자를 호출해야 한다.
2) 버스 클래스 구현
public class Bus {
int busNumber;
int passengerCount ;
int money;
public Bus(int busNumber) {
this.busNumber = busNumber; //버스 번호를 매개변수로 받는 생성자
}
public void take(int money) {
this.money += money; //버스 수입 증가
passengerCount++; //승객 수 증가
}
public void showInfo() {
System.out.println("버스" +busNumber + "번의 승객은" + passengerCount +"명이고, 수입은" +money+"입니다.");
}
}
버스의 멤버 변수 : 버스 번호, 승객 수, 버스가 받는 요금 총액
3) 지하철 클래스 구현
public class Subway {
String lineNumber;
int passengerCount ;
int money;
public Subway(int busNumber) {
this.lineNumber = lineNumber; //지하철 노선을 매개변수로 받는 생성자
}
public void take(int money) {
this.money += money;
passengerCount++;
}
public void showInfo() {
System.out.println(lineNumber + "의 승객은" + passengerCount +"명이고, 수입은" +money+"입니다.");
}
}
4) 학생, 버스, 지하철 객체 협력
public class TakeTrans {
public static void main(String[] args) {
Student studentDongjae = new Student("Dongjae", 5000); //학생 두명 생성
Student studentDonggu = new Student("Donggu", 10000);
Bus bus100 = new Bus(100); //노선 번호 100번 버스 생성
studentDongjae.takeBus(bus100); //dongjae가 100번 탑승
studentDongjae.showInfo(); //dongjae 정보 출력
bus100.showInfo(); //버스 정보 출력
Subway subwayGreen = new Subway("2호선"); //2호선 지하철 생성
studentDonggu.takeSubway(subwayGreen); //donggu가 2호선 탑승
studentDonggu.showInfo(); //donggu 정보 출력
subwayGreen.showInfo(); //지하철 정보 출력
}
}
객체 간 협력은 학생, 버스, 지하철 사이에 이루어졌다.학생은 버스, 지하철을 이용할 수 있다.
객체를 클래스로 만들어 구현하면 객체 사이에는 서로 어떤 값을 주고받고 메서드를 호출하는 일이 생긴다.
3. static 변수
변수를 여러 클래스에서 공통으로 사용하려면 'static 변수' 로 선언해 준다.
static 변수는 프로그램이 실행되어 메모리에 올라갔을 때 딱 한 번 메모리 공간이 할당된다.
그 값은 모든 인스턴스가 공유한다.
일반 멤버 변수는 인스턴스가 생성될 때마다 새로 생성되어 각각 다른 변수 이름을 가지게 되지만,
static로 선언한 변수는 인스턴스 생성과 상관없이 먼저 생성되고 그 값을 모든 인스턴스가 공유하게 된다.
이런 이유로 static 변수를 클래스에 기반한 변수라고 해서 '클래스 변수'라고 한다.
클래스 메서드
static 변수를 위한 메서드가 있는데 'static 메서드' 또는 '클래스 메서드'라고 한다.
클래스 메서드 내부에서 지역 변수와 클래스 변수는 사용할 수 있지만,
인스턴스 변수는 사용할 수 없다.
클래스 메서드에서 인스턴스 변수를 사용할 수는 없지만, 반대로 일반 메서드에서는 클래스 변수를 사용할 수 있다.
이유는 일반 메서드는 인스턴스가 생성될 때 호출되는 메서드이고, 클래스 변수는 이미 만들어진 변수이기 때문에 일반 메서드에서도 클래스 변수를 호출할 수 있기 때문이다.
4. 변수 유효 범위
지역 변수 : 함수나 메서드 안에서만 사용할 수 있다.
멤버 변수 : 클래스 안에서 사용할 수 있다.
static 변수 : 여러 인스턴스에서 공통으로 사용할 수 있다.
1) 지역 변수의 유효 범위
지역 변수는 함수나 메서드 내부에 선언하기 때문에 함수 밖에서는 사용할 수 없다.
지역 변수가 생성되는 메모리를 스택(stack)이라고 한다.
스택에 생성된 지역 변수는 함수가 호출될 때 생성되었다가 함수가 반환되면 할당되었던 메모리 공간이 없어진다.
2) 멤버 변수(인스턴스 변수)의 유효 범위
멤버 변수는 클래스가 생성될 때 힙(heap)메모리에 생성되는 변수이다.
멤버 변수는 클래스의 어느 메서드에서나 사용할 수 있다.
힙(heap)에 생성된 인스턴스가 가비지 컬렉터에 의해 수거되면 메모리에서 사라진다.
따라서 클래스 내부의 여러 메서드에서 사용할 변수는 멤버 변수로 선언하는 것이 좋다.
3) static 변수의 유효 범위
사용자가 프로그램을 실행하면 메모리에 프로그램이 상주한다.
이 때 프로그램 영역 중에 데이터 영역이 있다.
이 데이터 영역에는 상수, 문자열, static 변수가 생성된다.
인스턴스 변수는 new가 되어야 생성되지만, static 변수는 클래스 생성과 상관없이 처음부터 데이터 영역에 생성된다.
따라서 인스턴스 변수와 static 변수는 사용하는 메모리가 다르다.
이렇게 생성된 static 변수는 private가 아니면 클래스 외부에서도 객체 생성과 무관하게 사용할 수 있다.
static 변수는 프로그램이 시작-종료때까지 메모리에 상주하므로 크기가 너무 큰 변수를 static으로 선언하는 것은 좋지 않다.
5. 싱글톤 패턴
객체 지향 프로그램에서 인스턴스를 하나만 생성하는 디자인 패턴을 싱클톤 패턴이라고 한다.
static을 응용하여 프로그램 전반에서 사용하는 인스턴스를 하나만 구현하는 방식을 구현하려고 한다.
※싱글톤 패턴으로 회사 클래스 구현
1) 생성자를 private로 만들기
public class Company {
private Company() {}
}
싱글톤 패턴에서는 생성자를 반드시 명시적으로 만들고
그 접근 제어자를 private으로 지정해야한다.
private이므로 외부 클래스에서 마음대로 Company 인스턴스를 생성할 수 없게 된다.
company 클래스 내부에서만 이 클래스의 생성을 제어할 수 있다.
2) 클래스 내부에 static으로 유일한 인스턴스 생성하기
public class Company {
private static Company instance = new Company(); //유일하게 생성한 인스턴스
private Company() {}
}
이 인스턴스가 싱글톤 프로그램에서 사용할 유일한 인스턴스가 된다.
또한 private으로 선언하여 외부에서 접근을 제한해야 인스턴스 오류를 방지할 수 있다.
3) 외부에서 참조할 수 있는 public 메서드 만들기
public class Company {
private static Company instance = new Company(); //유일하게 생성한 인스턴스
private Company() {}
}
public static Company getInstance() { //인스턴스를 외부에서 참조할 수 있도록
if(instance == null) { public get() 메서드 구현
instance = new Company();
}
return instance; //유일하게 생성한 인스턴스 반환
}
}
privat으로 선언한 유일한 인스턴스를 외부에서도 사용할 수 있도록 설정해야 한다.
public 메서드를 생성한다.
유일하게 생성한 인스턴스를 반환해준다.
이 때 인스턴스를 반환하는 메서드는 반드시 static으로 선언해야 한다.
이유는 getInstance()메서드는 인스턴스 생성과 상관없이 호출할 수 있어야 하기 때문이다.
'java일지' 카테고리의 다른 글
자바 리마인드#8 배열2, ArrayList 클래스 (0) | 2023.01.19 |
---|---|
자바 리마인드#7 배열1, ArrayList (0) | 2023.01.17 |
자바 리마인드#5 클래스와 객체1 (0) | 2023.01.06 |
자바 리마인드#4 제어 흐름 이해하기 (0) | 2023.01.02 |
자바 리마인드#3 연산자 (0) | 2023.01.01 |