[소.자.바] 4.6 this의 개념(완료)
* 본 블로그는 개인 공부용으로 해당 내용은 자북의 '최영관'님이 저자이신 소설같은 자바를 읽고 정리한 내용으로써 문제가 있을 시 모두 내리도록 하겠습니다.
4.6.1 this란?
this란 클래스 내에서 클래스가 가지고 있는 멤버필드 또는 멤버 메소드를 직접 참조할 수 있는 자신의 참조 변수이다. 이게 무슨 말이냐구요? 그럼 이제 이게 무슨말인지 알아보는 시간을 가져보도록 하죠. this를 사용할 때는 3가지 방법이 있는데 그 예는 다음과 같습니다.
■ this.멤버필드, this.멤버 메소드
■ this
■ this(매개변수);
이 예들을 살펴보면서 this의 개념에 접근해 봅시다.
*멤버필드 : 클래스 내부에 존재하는 변수로써 변수와 상수(속성 즉, '데이터'라고도 하는데 여기에 객체가 생성되어질 때 그 객체의 특징적인 속성을 담아(저장)두는 역할을 합니다.
Java 클래스 구성요소(멤버필드와 멤버메서드)
Member Field와 Member Method 클래스를 구성하는 요소 중 멤버 필드에 대해 알아보자. 클래스는 객체가 가지는 속성을 저장하기 위해 필드(변수)를 포함한다. 다음 예제를 보자. 앞에서 클래스와 객체에 대한..
blog.itthis.me
- 70 -
4.6.2 this의 의미
먼저 this에 대한 정의부터 이해해보도록 하자. this는 다음과 같이 풀어서 이야기할 수 있다.
■ 클래스 내에서 클래스가 가지고 있는 변수나 메소드를 직접 참조할 수 있다.
■ 클래스 내에서 자신의 멤버들을 이용할 수 있는 것은 당연한 일이다.
■ 자신을 참조하는 객체변수 this를 이용하여 멤버를 이용할 수 있다.
■ 디자인 타임에 자기 자신을 직접 참조할 수 있는 객체변수이다.
■ 디자인 타임에 자기 자신을 참조할 수 있는 유일한 키워드이다.
자기가 자기 자신을 참조한다는 의미가 무엇일까? 분명히 여러분은 this를 클래스의 디자인 타임에 사용할 수 있다. this는 디자인 타임에 사용하는 것이지 실행타임에 직접 여러분이 사용하는 것은 아니다. 자바 가상 머신이 사용하는 것이라고 말할 수 있다.
클래스를 디자인 할 때는 아직 메모리가 할당되지 않은 순간이다. 하지만 언젠가는 할당이 될 것이다. 그러나 언젠가 할당이 될 주소의 참조값은 아직 미정이다. 객체를 생성하기 전 단계에 그 주소를 this라고 칭하고 할당되는 순간 this는 할당되는 메모리의 참조값을 갖게 된다면 this는 디자인 타임에 실행타임의 주소를 아는 것처럼 행동할 수 있다. 그렇다면 이렇게 해 보자. this를 "언젠가 생성되어질 내 주소 this의" 라는 간단한 단어로 바꾸어 해석해 보는 것이다.
(이를 곰곰히 생각해 보았을 때, 이런 예를 들 수 있을까 싶다. 아주 유명한 빵집이 있고 나는 그 빵집에서 제일 맛있는 빵을 사고 싶다. 하지만 아직 빵집이 문을 안 열어서 개인 전화로파티시에게 전화를 걸어 당신이 오늘 만들 제일 맛있는 빵을 찜하고 싶습니다. 그 빵을 제가 사 갈테니 예약명단 제일 위에 제 이름을 써주세요! 이런 느낌이 아닌가...라는 생각을 해보았다. 아..니면 말고;;;)
위의 그림은 this가 초기화 되는 순간을 보여주고 있는데, 디자인 타임에서 클래스는 아직 데이터 타입이기 때문에 메모리를 할당하지 않은 상태이다. 클래스가 객체를 생성하여 메모리를 갖는 순간 생성된 메모리의 참조값을 객체변수가 가지게 된다.
■ Top a = new Top();
■ Top b = new Top();
■ Top c = new Top();
■ Top d = new Top();
위 그림에서는 4개의 참조값 a, b, c, d가 생성되는 과정을 보여주고 있다. 문제는 이 참조 값들은 메모리가 생성되는 순간의 참조값이라는 것이다. 이것은 일반적인 방법이다. 하지만, this는 디자인 타임에 자신을 참조할 수 있는 참조값이다. 디자인 타임에 클래스의 메모리가 생성되냐는 질문에는 '아니오'로 그저 하나의 형태를 가질 뿐이다. 그렇다면 어떻게 this가 생성되지도 않은 자신을 참조할 수 있을까?
잘 생각해보자. 디자인 타임의 참조값은 아직은 비어있다고 가정하고 실행할 때 (과연)this에다 각각의 객체가 할당받은 값을 넣어준다면 하나의 this가 메모리에 생성되는 순간 각각의 객체에 대한 this가 되지 않겠냐는 말이다!
this라는 객체변수는 아직 만들어지지도 않은 자신의 참조값이라는 가정 하에 클래스 내에서 사용된다. 그리고 메모리가 생성되면 그 때 객체변수가 가지는 값과 같은 참조값을 가지게 되는 것이다. 이렇게 함으로써 디자인 타임에 하나의 이름으로 자신을 참조하고 실행 타임에서는 각각에 적용되어질 수 있다.
4.6.3 this.멤버필드, this.멤버 메소드
this의 사용법 중에서 this를 이용하여 자신을 참조하는 방법을 알아보도록 하자. 클래스 내에서 사용되어지는 멤버필드와 멤버 메소드를 사용할 때 this를 사용하는 것과 사용하지 않는 것은 동일하다. 귀찮기 때문에 this를 사용하지 않지만 this를 표시한다면 코드는 더욱 명확해진다. 코드가 길어지면 사용하는 변수가 클래스의 멤버필드인지 아니면 지역분수인지 혼동 될 수가 있다. 만약 this.를 이용한다면 아주 간단히 멤버인지 아닌지를 구분할 수 있다.
디자인 타임의 this는 공통된 this이지만 실행 타임의 this는 생성되어지는 객체 변수의 참조값과 같은 값을 가지기 때문에 각각의 this가 되는 것이다. 아직 생성도 되지 않은 메모리에 대한 참조값을 this라는 객체변수가 나중에 메모리가 생성되면 가질 것이라는 가정 하에 사용하는 것이니 this를 사용하여 멤버에 접근하든지...결론적으로, 결국에는 '같은 것'이라는 소리다. 일단 예를 살펴보도록 하자.
ThisTest.java //this(사용법)를 테스트 하기 위한 예제
public class ThisTest{
private int number;
private String name;
public ThisTest(String name, int number){
//this를 이용한 매개변수와의 구분(this.name은 안에 name이고, 그냥 name은 매개변수 임을 뜻함)
this.name = name;
this.number = number;
}
public void print(){
System.out.println("-- this를 이용한 멤버 테스트 --");
System.out.println("name : " + this.name + " number : " + this.number);
}
public void myprint(){
System.out.println("-- this를 이용한 메소드 테스트 --");
this.print();
}
public static void main(String[] args){
ThisTest th = new ThisTest("홍길동", 20);
th.print();
th.myprint();
}
}
- 72 -
C:\examples\4.Class for Basic Java>javac ThisTest.java
C:\examples\4.Class for Basic Java>java ThisTest.java
name : 홍길동 number : 20
-- this를 이용한 메소드 테스트 --
name : 홍길동 number : 20
이 ThisTest 클래스에서는 두 개의 멤버필드를 가지고 있다. 이 멤버필드에 접근하는 방법은 클래스 내에서는 name과 number를 사용하고 싶은 곳에 마음대로 이용함으로써 사용할 수 있다. 하지만 생성자 메소드 쪽을 살펴보면 name이 중복되어 있다는 것을 알 수 있다. 이것을 구분하기 위한 방법으로 this를 사용하게 되는데 이때는 멤버라는 의미다. 위 예제의 생성자 부분에서는 이러한 변수의 애매성을 명확하게 해결하고 있다.
public ThisTest(String name, int number){
//this를 이용한 매개변수와의 구분(this.name은 안에 name이고, 그냥 name은 매개변수 임을 뜻함)
this.name = name;
this.number = number;
}
매개변수의 이름도 name이고 멤버필드의 이름도 name이다. 언어적인 원리에 의하면 가까운 변수가 더 큰 영향력이 있다. this를 붙이지 않으면 생성자 메소드 내에 존재하는 name은 모두 매개변수의 name이다. 이렇게 된다면 외부에서 들어오는 데이터를 멤버필드에 넣을 수가 없어진다. 만약에 this를 붙인다면 this는 언젠가 생성되어질 내 주소 this의 name이 되어 버린다. 이렇게 되면 당연히 this.name은 멤버 변수의 name이 되기 때문에 별 다른 노력없이 변수의 이름이 같아도 니꺼 내꺼를 확실하게 구별 지을 수 있다. name과 number는 생성자 메소드의 매개변수를 말하는 것이며 this.name과 this.number는 멤버필드를 가르키는 것이다.
this라는 키워드는 멤버라는 것을 아리는 하나의 표시 방법이지만 만약 위의 상황처럼 특수한 경우가 아니면 this라는 키워드를 사용하지 않아도 무방하다. 하지만 this 키워드를 사용하여 어느 소속의 메소드인지 아니면 변수인지를 분명히 한다면 코드는 더욱 명확해진다. 이 말은 곧, 클래스 내에 모든 멤버는 this를 사용할 수 있으며 사용하지 않아도 상관은 없다는 말이다.
4.6.4 this
this가 혼자서 이용되면 자신의 참조값을 의미한다. 하지만 이 참조는 디자인 타임에서 적용되어지지만 결국에 this는 언젠가 만들어질 메모리의 참조값 this이다. 즉, 이 말은 실행 타임에 this 자체는 객체를 생성할 때 객체 변수가 가지는 값과 같은 값을 가지게 된다. 생성될 객체의 참조값을 의미하는 것이다. this +자체를 사용하는 예제를 살펴보자.
* 참조값이란 객체의 메모리를 생성했을 때 메모리와 연결된 유일한 숫자값이라 한다.
(출처: https://dohe2014.tistory.com/entry/참조reference와-참조변수reference-variable [돕자클럽])
- 73 -
SpecialThis.java //this를 테스트하기 위한 예제
public class SpecialThis{
private int i = 0;
public void plusCount(){
i++;
}
public SpecialThis getMySelf(){
return this;
}
public void print(){
System.out.println("memberi = " + this.i);
}
public static void mian(String args[]){
SpecialThis st = new SpecialThis();
SpecialThis st2 = st.getMySelf();
st.print();
st.plusCount();
st.print();
st2.plusCount();
st2.print();
st.plusCount();
st.prtin();
}
}
C:\examples\4.Class for Basic Java>javac SpecialThis.java
C:\examples\4.Class for Basic java>java SpecialThis
member i = 0;
member i = 1;
member i = 2;
member i = 3
this라는 키워드가 없다면 클래스는 현재 디자인 타임이기 때문에 자신을 참조할 방법은 없다. 잘 생각해 보자. 아직 만들어지지도 않은 자신을 어떻게 참조할 수 있나? this라는 키워드는 그저 this.메버필드, this.멤버 메소드 이렇게 사용하는 것이 아니라 객체가 메모리를 할당 받는 순간에 객체변수가 가지는 값과 똑같은 값을 가지기 때문에 this 자체는, 디자인 타임에 자신을 가르키는 자기 자신의 객체 변수라고 보면 된다.
public Specialthis getMySelf(){
return this;
}
- 74 -
위의 이 메소드는 객체가 생성되어진 후 호출 할 수 있다. 그리고 this는 객체가 생성되어지면 객체 변수의 값과 같은 참조 값을 가지게 된다. 그러니 this는 자신의 형은 현재 클래스의 데이터 타입과 같다. 메소드의 리턴 타입과 리턴 되어지는 것은 같아야 한다. 여기서 this의 타입은 자신의 참조변수이기 때문에 SpecialThis 데이터 타입이다. 그리고 자신을 리턴하고자 한다면 "return this;"라고 하면 된다.
4.6.5 this()
this()는 클래스 자신의 생성자 메소드를 호출할 때도 사용한다. 클래스 내에서 유일하게 호출할 수 없는 메소드가 있다. 이 메소드가 바로 생성자 메소드이다. 이것을 호출하는 방법을 제공하는 것이 바로 this이다. 아래는 This를 이용하여 생성자 메소드를 호출하고 있는 예제이다.
ThisSelf.java //this를 테스트하기 위한 예제
public class ThisSelf{
private String name;
private int age;
public ThisSelf(){
this(이름없음");
}
public ThisSelf(String name){
this(name, -1);
}
public ThisSelf(String name, int age){
this.name = name;
this.age = age;
System.out.println("name : " + name + " number : " + age);
}
public static void main(String[] args){
ThisSelf ts1 = new ThisSelf();
ThisSelf ts2 = new ThisSelf("홍길동");
ThisSelf ts3 = new ThisSelf("김삿갓", 50);
}
}
C:\examples\4.Class for Basic Java>javac ThisSelf.java
C:\examples\4.Class for Basic Java>java This.self
name : 이름없음 number : -1
name : 홍길동 number : -1
name : 김삿갓 number : 50
ThisSelf 클래스의 디폴트 생성자를 호출 했을 때
■ this("이름없음")은 ThisSelf(String name) 메소드를 호출한다.
■ 그리고 ThisSelf(String name) 생성자는 다시 this(name, -1)이라는 곳에서 ThisSelf(String name, int age)를 호출한다.
생성자 메소드는 아무나 호출할 수 있는 것이 아니다. 객체의 생성 당시 여러분이 new와 같이 명시해 주는 것이 생성자 메소드이다. 그 외의 경우 생성자 메소드를 호출할 수 있는 방법은 이 방법 밖에 없다. 디폴트 생성자를 호출하였지만 디폴트 생성자는 자신의 클래스 내에 다른 생성자를 this를 사용해서 호출하고 있다.
그런데 왜 이렇게 복잡한 방법을 이용하고 있을까? 왜 자신의 생성자 메소드를 이렇게 복잡하게 호출하고 있는걸까? 이는 자신의 생성자를 재이용하는 것에 있다. 클래스를 만들다 보면, 상당히 많은 작업을 하나의 생성자에서 처리했다면 다른 생성자에서도 다시 많은 작업을 해주어야만 한다. 여러분이 클래스를 디자인하다 보면 이러한 현상은 자주 일어나게 되는데, 물론 이것은 생성자 중복이 발생할 때 나타나는 문제이다. 그런데 자신의 생성자 메소드를 호출할 수 있는 방법은 없고, 작업은 중복 되게된다면 객체지향의 기본 법칙을 위배하게 되는 것이다. 그래서 this를 이용해서 생성자 메소드를 호출하는 방법을 제공하고 있는 것이다. 여기서 가장 조심해야 하는 부분은 생성자 메소드에서 다른 생성자 메소드를 호출 할 때 생성자 메소드 호출은 제일 윗부분에서 사용해야 한다는 것이다.
4.6.6 결론
※this의 특징
■ 객체 자신에 대한 참조값을 갖는다.
■ 매개 변수와 객체 자신이 가지고 있는 변수의 이름이 같을 경우 이를 구분하기 위해 자신이 가지고 있는 변수 앞에
this를 사용한다.
■ 객체 생성자 내에서 다른 생성자를 호출하기 위해서 사용한다.
■ 객체 자신에 대한 참조값을 메소드에 전달하거나 리턴해 주기 위해 사용하기도 한다.
■ 디자인 타임의 this는 객체가 생성되어지는 순간에 객체변수가 가지는 값을 갖게 된다.
this를 사용함으로써, 모호하지 않고 좀더 명확하다 할 수 있는 프로그램을 작성할 수 있다.
더불어 api는 다른 사람이 만든 메소드이다.
*다음은 생성자에 관한 유투브 동영상과 블로그 글인데 필요하신 분은 한번 보시길 바란다.
(기본생성자가 필요한 이유. 먼저 내가 클래스를 만들고 기본생성자를 아직 만들어 주지 않더라도 얘가 자동으로 만들어짐으로써 그 클래스를 이용할 수 있게 해준다. 이는 모든 클래스는 반드시 하나 이상의 생성자가 정의되어 있어야 하기 때문인데 이 말은 다음 내용과 연결되어, 초기화를 해주는 역할, 즉 기본 생성자는 클래스의 인스턴스를 생성해 주기 때문이다.)
https://www.youtube.com/watch?v=Dohu9r5w2FE
생성자(Constructor)
이구자바의 스터디룸 생성자(Constructor) 지난 포스팅에서 클래스에서 인스턴트의 생성을 위해 잠시 스쳐...
blog.naver.com
※참고할 내용 : 새로운 클래스를 하나 만든다는 것은
= 새로운 데이터 타입 만드는 것
= 이 타입으로 변수를 선언/활용, 이때 클래스를 이용한 변수를 객체 또는 객체 변수라 한다.(object)
* 객체(객체변수)는 기본 데이터 변수와 다르다. 객체 변수 선언 후 메모리 생성해줘야 완전한 객체가 된다.
레퍼펀스 사이트(블로그) : https://m.blog.naver.com/PostView.nhn?blogId=heejery&logNo=60184041469&proxyReferer=https%3A%2F%2Fwww.google.com%2F
blog.naver.com