Notice
Recent Posts
Recent Comments
Link
«   2025/10   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Tags
more
Archives
Today
Total
관리 메뉴

백엔드 개발 공부 일지

JAVA Basic - CLASS와 객체 2 본문

Java 입문

JAVA Basic - CLASS와 객체 2

JungCat 2022. 11. 26. 01:04

● This 예약어

this가 뭔데?

1) 자신의 메모리를 가리키는 this

this는 간단히 설명해, 생성된 인스턴스 스스로를 가리키는 예약어이다.

아래의 코드를 통해, BirthDay class를 만들고 this와 BirthDayclass를 출력해본다.

package thisex;

class BirthDay{
	int day;
	int month;
	int year;
	
	// 태어난 연도를 지정하는 메서드
	public void setYear(int year) {
		this.year = year; // bDay.year = year; 와 같다
	}
	
	// this 출력 메서드
	public void printThis() {
		System.out.println(this);
	}
}

public class ThisExample {

	public static void main(String[] args) {
		BirthDay bDay = new BirthDay();
		bDay.setYear(2000);
		System.out.println(bDay);
		bDay.printThis();
	}

}

그러면 아래 출력값과 같이 둘다 동일하게 클래스이름@메모리주소의 문자열값이 나오게된다.

즉, this는 그 인스턴스(객체) 그자체를 가리키는 말이다.

thisex.BirthDay@2ff4f00f
thisex.BirthDay@2ff4f00f

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

클래스에서 생성자가 여러개 있을 때 어떤 생성자에서 다른 생성자를 호출하는 경우가 종종 발생한다.

아래의 코드는 this를 사용해 Person(String, int) 생성자를 호출하는 내용이다.

package thisex;

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() 디폴트 생성자가 호출되는 경우 "이름 없음"과 1의 값을 대입하고자 하여 작성된 코드이다.

물론, 디폴트생성자 안에 직접 초기값을 작성하여도 되지만 this를 활용하여 생성자를 호출하는 방식으로 사용할수 있다.

이름 없음
1

(주의 사항) 다른 생성자를 호출하는 this는 항상 디폴트 생성자에서 가장 먼저 작성되어야 한다.

디폴트 생성자에서 생성이 완료되는 것이 아니라 this를 사용해 다른 생성자를 호출하므로, 생성이 완료되지 않은 시점에 다른 코드가 있으면 오류가 난다.

 

3) 자신의 주소를 반환하는 this

마지막으로 this를 사용하여 생성된 클래스 자신의 주소 값을 반환할 수 있다.

인스턴스 주소 값을 반환할 떄 this를 사용하고 반환형은 클래스 자료형을 사용한다.

 

package thisex;

class Person{
	String name;
	int age;
	
	Person(){
		this("이름 없음", 1); // this를 사용해 Person(String, int)생성자 호출
	}
	
	Person(String name, int age){
		this.name = name;
		this.age = age;
	}
	
    // 반환형이 클래스인 메서드 생성
	Person returnItSelf() {
		return this; // 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); // 참조 변수 출력
	}

}
이름 없음
1
thisex.Person@2ff4f00f
thisex.Person@2ff4f00f

위의 2방법과 달리 this를 반환하는 메서드를 사용할 일은 흔하지는 않지만 클래스 자료형과 상관없이 클래스 내에서

this를 사용하면 자신의 주소값을 반환할 수 있다는 것만 알아두자.

 

● 객체간 협력

OOP에서는 객체를 정의하고 객체간 협력의 프로그래밍이 이루어진다.

 

아래는 학생, 버스, 지하철과 관련된 세개의 객체를 만든 뒤 객체간 협력을 수행한 예시 코드이다.

 

학생 클래스

package cooperation;

public class Student {
	
	public String studentName; // 학생 이름
	public int grade; //학년
	public int money; // 학생이 가지고 있는 돈
	
	// 학생 이름과 가진 돈을 매개변수로 받는 생성자
	public Student(String studentName, int money) {
		this.studentName = studentName;
		this.money = money;
	}
	
	// 학생이 버스를 타면 1000원을 지불하는 기능을 구현한 메서드
	public void takeBus(Bus bus) {
		bus.take(1000);
		this.money -= 1000;
	}
	
	public void takeSubway(Subway subway) {
		subway.take(1500);
		this.money -= 1500;
	}
	//학생의 현재 정보를 출력하는 메서드
	public void showInfo() {
		System.out.println(studentName + "님의 남은 돈은" + money + "입니다.");
	}

}

버스 클래스

package cooperation;

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 + "입니다.");
		
	}
}

지하철 클래스

package cooperation;

public class Subway {
	String lineNumber; // 지하철 호선
	int PassengerCount; // 지하철 승객 수
	int money; // 지하철 수입
	
	public Subway(String lineNumber) {
		this.lineNumber = lineNumber;
	}
	
	public void take(int money) {
		this.money += money;
		PassengerCount++;
	}
	
	public void showInfo() {
		System.out.println(lineNumber+"의 승객은" + PassengerCount + "명이고, 수입은" + money + "입니다.");
	}

}

 

세개의 객체를 협력하는 main 함수

package cooperation;

public class TakeTrans {

	public static void main(String[] args) {
		Student student1 = new Student("Tom hoddy", 10000);
		Student student2 = new Student("Jesica Jones", 15000);
		
		Bus bus100 = new Bus(100);
		student1.takeBus(bus100);
		student1.showInfo();
		bus100.showInfo();
		
		Subway subwayGreen = new Subway("2호선");
		student2.takeSubway(subwayGreen);
		student2.showInfo();
		subwayGreen.showInfo();
	}

}
Tom hoddy님의 남은 돈은9000입니다.
버스100번의 승객은1명이고 수입은1000입니다.
Jesica Jones님의 남은 돈은13500입니다.
2호선의 승객은1명이고, 수입은1500입니다.

위의 예시는 세개의 객체가 협력하는 방식의 기본적인 개념을 아주 잘 설명하고 있는 듯 하다.

 

학생클래스에서는 학생과 관련있는 학생의 신분과 가지고 있는 금액을 다루며 버스와 지하철의 클래스도 각각의 수입과 승객들을 작성한다.

 

그 후, 메인 메서드에서 생성한 객체들과 객체의 메서드를 활용하여 프로그래밍을 할 수 있다.

 

여기서 moeny라는 변수는 모든 클래스에서 선언되어지는데 동일한 변수로 사용되어지진 않는다.

default로 접근 제어자를 쓰지 않을경우 해당하는 package에서 접근은 가능하나 클래스명.money로 사용되어 지기 때문에 동일한 변수명임에도 불구하고 각기 다르게 사용되어 질 수 있는듯 하다.

 

● static 변수

위의 예시에서 만약 학생마다의 고유한 학번을 가지며 학생이 입학(클래스가 생성)하는 경우에 학번이 자동으로 생성되도록 만들고싶다면 어떻게 해야할까? (학번은 생성된 인스턴스 순서대로 부여가 되어야 한다면)

 

이 경우에 따로 변수를 생성하는 것이 아닌 클래스 전반에서 공통으로 사용할 수 있는 기준 변수가 필요하다.

기준변수를 활용하여 학번이 생성될때마다 하나씩 증가시켜 각 학생 인스턴스의 학번변수에 대입해주면 되는데, 이떄 클레스에서 공통으로 사용하는 변수를 'static  변수' (정적 변수 or 클래스 변수) 라고 한다.

 

static        int          serialNum

예약어  자료형       변수 이름

 

static 변수는 다른 멤버 변수와는 다르게 생성될 때 ' 딱 한번 ' 메모리 공간이 할당되며 그 값을 모든 인스턴스가 공유한다.

package staticex;

public class Student {

	public static int serialNum = 1000; // static 변수는 인스턴스 생성과 상관없이 먼저 생성됨
	public int studentID;
	public String studentName;
	public int grade;
	public String address;

	public String getStudentName() {
		return studentName;
	}

	public void setStudentName(String name) {
		studentName = name;
	}

}
package staticex;

public class StudentTest {
	public static void main(String[] args) {
		Student studentLee = new Student();
		studentLee.setStudentName("이지원");
		System.out.println(studentLee.serialNum);// serialNum의 초기값 출력
		studentLee.serialNum++;

		Student studentSon = new Student();
		studentSon.setStudentName("손수경");
		System.out.println(studentSon.serialNum);// serialNum의 초기값 출력
		System.out.println(studentLee.serialNum);// serialNum의 초기값 출력

	}

}
1000
1001
1001

위와 같이 static 변수로 생성된 serialNum은 동일한 메모리를 공유하는것을 확인할 수 있다.

 

학번 부여와 같은 문제를 해결하기 위해서 Student class에 다음과 같은 생성자를 추가해주면 된다.

	public Student() {
		serialNum++;
		studentID = serialNum;
	}

 

※ Static 변수(클래스 변수)는 인스턴스보다 먼저 생성되므로 참조하기 위해서는 클래스 이름을 사용하는게 옳다.

(인스턴스 사용시 에러는 안뜨지만 노란색 경고줄이 나온다.)

※ Static 변수에 관한 get, set 메서드를 만들기 위해서는 클래스 메서드(static method)를 사용하면 된다.

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

(인스턴스는 나중에 생성되기 떄문에 발생하는 에러인듯 하다.)

※ 클래스메서드와 클래스변수는 인스턴스가 생성되지 않아도 호출이 가능하다.

 

● 변수 유효 범위

지금까지 배운 JAVA의 변수는 총 세가지 종류이다.

 

지역 변수 (local 변수)

지역 변수는 메서드 내부에서 선한하기 때문에 함수 안에서만 사용이 가능하다.

(다른 함수에서 사용이 불가능하다)

 

지역변수가 생성되는 메모리는 스택메모리라고 하며 스택에서 생성되는 지역 변수는 함수가 호출될 떄 생성되었다가 함수가 반환되면 할당되었던 메모리공간이 해제되면서 함께 없어진다.

멤버 변수 (instance 변수)

멤버 변수는 클래스의 어느 메서드에서나 사용이 가능하다.

(클래스 외부에서 사용하기 위해서는 메서드를 활용하거나 생성자를 활용해야겠죠? (참조변수로써 활용))

 

클래스가 생성될 때 힙 메모리에 생성되는 변수이며 힙에 생성된 인스턴스가 가비지 컬렉터에 의해 수거되면 메모리에서 사라진다. 

(따라서 클래스 내부의 여러 메서드에서 사용할 변수는 멤버변수로 선언하는것이 좋다.)

static 변수 (class 변수)

static변수는 private이 아니라면 클래스 외부에서도 객체 생성과 무관하게 사용할 수 있다.

 

static변수는 배웠던 바와 같이 처음부터 데이터 영역 메모리에 생성이 되어 인스턴스 변수와는 사용하는 메모리가 다르다.

데이터영역은 프로그램이 실행되는동안 쭉 존재하기 때문에 프로그램을 종료해야 메모리가 소멸되게 된다.

 

● static 응용 - 싱글톤 패턴

프로그램을 구현하다 보면 단 하나의 인스턴스 만 필요한 경우가 발생한다.

 

이 경우 활용하는 '디자인 패턴' 중의 하나를 '싱글톤 패턴' 이라고 하며 아래는 그 예제이다. 

(디자인 패턴 : 객체 지향 프로그램을 더 유연하고 재활용성이 높게 하기 위해서 이론화한 내용)

 

package singleton;

public class Company {

	private static Company instance = new Company(); // 유일하게 생성된 인스턴스 (내부에서 생성)

	// 외부에서 여러개의 인스턴스 생성을 방지 하기 위해 private으로 생성
	private Company() {} 

	// 외부에서 참조 할 수 있는 public 메서드 만들기
	// getInstance는 인스턴스 생성과 상관없이 호출할 수 있어야 하기 때문에 반드시 static 사용
	public static Company getInstance() {
		if (instance == null) {
			instance = new Company();
		}
		return instance; // 유일하게 생성한 인스턴스 봥환
	}
}
package singleton;

public class CompanyTest {
	public static void main(String[ ] args) {
		Company myCompany1 = Company.getInstance( );
		Company myCompany2 = Company.getInstance( );
		
		System.out.println(myCompany1==myCompany2);
	}

}
true

'Java 입문' 카테고리의 다른 글

JAVA Basic - 인터페이스  (0) 2022.12.08
JAVA Basic - 추상 클래스  (0) 2022.12.08
JAVA Basic - 상속  (0) 2022.12.07
JAVA Basic - 배열  (0) 2022.11.28
JAVA Basic - CLASS와 객체 1  (0) 2022.11.25
Comments