참조변수 this
- this 는 인스턴스 자신을 가리키는 일종의 참조변수이다.
* this에는 인스턴스 본인의 주소값이 저장되어 있다. - 참조변수를 통해서 객체의 변수에 접근할 수 있다는 사실은 당연한 개념이다.
마찬가지로, 참조변수 this 를 통해서도 객체의 변수에 접근할 수 있다.
this . iv_이름 - 클래스를 작성 할 때, 필드에 선언된 iv를 클래스 내부에서 사용할 때, 우리는 " iv_이름 " 만으로 그 값을 사용한다.
하지만, 사실 컴파일러가 우리를 대신해서 몰래 " iv_이름 " 앞에 추가해주는 것이 있다.
바로 참조변수 this 가 컴파일러에 의해서 자동으로 추가 된다. - 즉, 원래는 iv 를 클래스 내부에서 사용할 때 마다, 항상 this. 를 변수 앞에 붙여야하지만, 이를 컴파일러가 자동으로 추가해주기 때문에 우리는 편리하게 this. 을 생략한 채로 iv 를 사용할 수 있었던 것이다.
- 단, lv 와 iv의 이름이 같을 경우에는 이 둘을 구별하기 위해서 iv 앞에 참조변수 this 를 꼭 사용해야 한다.
아래 코드를 보면 무슨 뜻인지 바로 이해 할 수 있다.
1
2
3
4
5
6
7
8
9
|
class person {
static int age; // iv의 이름이 age 이다.
String name;
person(int age, String name) { // lv의 이름 또한 age 이다.
this.age = age; // iv와 lv를 구분해주기 위해서 iv 앞에 참조변수 this를 붙인다.
// age = age; ---> 불가능한 코드 this.name = name;
}
}
|
cs |
- 참조변수 this 는 인스턴스 메서드(생성자 포함)에서만 사용할 수 있다.
* 참조변수 this 는 객체 자신을 가리키므로 인스턴스의 생성 없이도 호출이 가능해야하는 스태틱 메서드에서는 당연히 참조변수 this를 사용 할 수 없다. - 참조변수 this 는 스태틱 메서드에서는 사용할 수 없다.
생성자 this()
- 생성자 this() 는 생성자 내부에서 다른 생성자를 호출할 때 사용한다.
- 반드시, 생성자 내부에서 첫 줄 에서만 사용할 수 있다.
- 아래의 코드를 보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class person {
int age;
String name;
person() {
this(1,"baby"); // person(int age, String name) 생성자를 호출한다.
}
person(int age, String name) {
this.age = age;
this.name = name;
}
}
|
cs |
- 위의 코드에는 생성자가 2개가 있다.
- person() 생성자 내부에 있는 this(1, "baby") 가 person(int age, String name) 생성자를 호출한다.
- this() 생성자는 생성자 내부에서 사용되었고, 내부 블럭의 첫 줄에서 사용되었다는 것을 확인할 수 있다.
참조변수 super
- 조상 클래스의 인스턴스 본인을 가리키는 일종의 참조변수이다.
* 참조변수 super에는 조상 클래스의 인스턴스의 주소값이 저장되어 있다. - 조상 클래스의 객체를 가리킨다는 점만 다르고, 그 외의 개념과 기능은 참조변수 this 의 그것과 동일하기 때문에 자세한 설명은 참조변수 this 의 설명을 참고하자.
- 조상 클래스의 iv와 자손 클래스의 iv의 이름이 같을 때, 이 둘을 구분해야 할 때는 반드시 참조변수 super을 사용해야 한다.
* 구분을 위해서 꼭 적어줘야 한다는 점 또한 참조변수 this와 개념이 비슷하다. 구분하는 대상만 서로 다를 뿐...
생성자 super()
- 자손의 생성자 내부에서 조상의 생성자를 호출해야 할 때 사용하며, 개념과 기능은 생성자 this()와 동일하다.
* 상속 시, 조상의 생성자와 초기화 블럭은 함께 상속되지 않는 다는 점을 기억해야한다. 그래서 조상의 생성자를 사용하기 위해서는 super()를 사용해야 하는 것이다. - 생성자 this()와 마찬가지로, super()를 사용하려면 생성자의 내부에서 첫줄에 사용해야 한다.
생성자 super() 를 사용해야 하는 경우는 다음과 같다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
|
class Point {
int x, y;
Point(){}
Point(int x, int y) {
this.x = x;
this.y = y;
}
}
class Point3D extends Point {
int z;
Point3D(int x, int y, int z) {
super(x,y);
// this.x = x;
// this.y = y;
this.z = z;
}
}
|
cs |
- Point3D(int x, int y, int z) 의 생성자에서 지역변수 x 와 y를 인스턴스변수 x 와 y 에 대입해야 할 때,
this.x = x; this.y = y; 와 같은 코드는 좋지 못하다. - 생성자 super()를 이용한 super(x, y)를 작성해서 조상의 생성자인 Point(int x, int y)를 호출한다.
생성자의 중요 개념 정리
- 인스턴스가 생성될 때 마다 호출되는 인스턴스 초기화( = iv 초기화) 메서드
* 객체의 생성은 생성자가 아니라, new 연산자의 역할임을 유의하자.
* 생성자 또한 메서드 이다. - 생성자도 메서드라서 "오버로딩"이 가능하다.
(클래스 내부에 여러 갯수의 생성자 작성이 가능한 것도 오버로딩 개념이 들어간 것)
* 오버로딩 : 메서드 이름은 동일하고 매개변수의 개수 및 타입 및 순서가 다른 메서드를 여러 갯수 작성하는 것. - 모든 클래스는 반드시 최소한 1개 이상의 생성자를 가져야한다.
- 클래스 내에 작성된 생성자가 없다면 컴파일러가 클래스 내에 기본생성자를 자동으로 추가해준다.
* 기본생성자란, 매개변수가 없는 생성자를 말한다. - 매개변수가 존재하는 생성자를 작성해둔 경우, 컴파일러가 기본생성자를 자동으로 추가해 주지 않는다.
* 이런 경우에는 작성자가 수동으로 기본생성자를 작성해야만 한다.
* 기본생성자는 반드시 만들어 줘야 한다고 생각해두자 = 습관화!! - 모든 생성자는 반드시 생성자 내부의 첫 줄에 다른 생성자를 호출해야 한다.
- 생성자 내부에 다른 생성자를 호출하는 코드를 작성하지 않는 경우, 컴파일러가 생성자 내부의 첫 줄에 조상의 기본 생성자인 super(); 를 자동 삽입해준다.
- 생성자 this() 와 super()는 반드시 생성자 내부의 첫 줄 에서만 사용 가능하다.
생성자의 중요 개념을 바탕으로 다음 코드의 출력 결과를 예상해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
class Parent {
int x = 100;
Parent() {
this(200);
}
Parent(int x) {
this.x = x;
}
int getX() {return x;}
}
class Child extends Parent {
int x = 3000;
Child() {
this(1000);
}
Child(int x) {
this.x = x;
}
}
|
cs |
1
2
3
4
5
6
|
class Solution {
public static void main(String[] args) {
Child c = new Child();
System.out.println("x = " + c.getX());
}
}
|
cs |
출력 정답 :
x = 200
- 9행의 return x ; 는 Parent 에 있는 인스턴스 변수인 x 를 반환시킨다.
** Parent의 모든 멤버를 Child가 상속 받았는데 왜 getX() 메서드가 Child 인스턴스변수 x 를 반환하는 것이 아닌지는 더 알아봐야할듯 하다.... - Parent의 x 에는 어떤 값이 저장되어 있는지 추적해보자.
- Child() 생성자가 호출되었으므로 13~15행의 Child() { this(1000); } 가 호출된다.
- 14행의 this(1000)을 통해서, 16~18행의 Child(int x) { this.x = x; } 가 호출된다.
- Child(int x) { this.x = x; } 생성자 내부의 첫줄에는 다른 생성자를 호출하는 코드가 없기 때문에 컴파일러가 조상의 기본생성자인 super()를 자동삽입하여 조상의 기본생성자를 호출시킨다.
- 3~5행의 Parent() { this(200); } 가 호출된다.
- 4행의 this(200) 을 통해서, 6~8행의 Parent(int x) { this.x = x; } 가 호출된다.
- 지역변수 x 에 200 을 저장했으므로 this.x = x; 를 통해서 Parent의 인스턴스 변수 x 에 200이 저장된다.
- 따라서 x = 200 이 출력된다.
생성자 호출 과정만 정리하자면 다음과 같을 것이다.
Child() 호출 → Child(int x) 호출 → super() 즉 Parent() 호출 → Parent(int x) 호출 → super() 즉 Object() 호출
참조변수 this, super 의 개념을 활용하여 다음 코드의 출력을 예상해보자.
1
2
3
4
5
6
7
8
9
10
11
12
13
|
class Parent {
int x = 100;
}
class Child extends Parent {
int x = 200;
void method() {
System.out.println(x);
System.out.println(this.x);
System.out.println(super.x);
}
}
|
cs |
출력 정답 :
200
200
100
- 9행의 x 는 this.x 와 동일한 코드이다. 왜냐하면, 컴파일러가 this. 을 자동추가 해주기 때문.(참조변수 this 개념 참고)
- 11행의 super.x는 조상의 인스턴스 변수 x 를 의미한다. (참조변수 super 개념 참고)
22년 12월 28일 수요일 학습
'Java 문법 개념' 카테고리의 다른 글
추상클래스 vs 인터페이스 (0) | 2023.01.11 |
---|---|
변수의 초기화 ( 자동초기화, 명시적초기화, 복잡초기화 ) (0) | 2022.12.29 |
오버로딩(Overloading) 과 오버라이딩(Overriding) (0) | 2022.12.29 |
Scanner 클래스의 next() , nextLine() 의 차이 (0) | 2022.12.27 |