super
▶ this – 인스턴스 자신을 가리키는 참조변수. 인스턴스의 주소가 저장되어있음
모든 인스턴스 메서드에 지역변수로 숨겨진 채로 존재
▶ super – this와 같음. 조상의 멤버와 자신의 멤버를 구별하는 데 사용.
상속받은 멤버와 자신의 클래스에 정의된 멤버의 이름이 같을 때는 super를 붙여서 구별.
조상 클래스로부터 상속받은 멤버도 자손 클래스 자신의 멤버이므로 super대신 this를 사용할 수 있다.
그래도 조상 클래스의 멤버와 자손 클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super 를 사용하는 것이 좋다.
모든 인스턴스메서드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조변수인 this와 super의 값이 된다.
static 메서드(클래스메서드)는 인스턴스와 관련이 없다. 그래서 this와 마찬가지로 super역시 static 메서드에서는 사용할 수 없고 인스턴스메서드에서만 사용할 수 있다.
예7)
public class SuperTest {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent {
int x = 10; // this.x, super.x
}
class Child extends Parent {
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x=" + super.x);
}
}
Child클래스에 멤버변수 x가 없다.
이 때 Child클래스의 인스턴스를 생성해서 method를 호출하면... 변수 x가 하나밖에 없기 때문에 선택의 여지가 없이
조상으로부터 상속받은 멤버변수 x를 의미한다. 그래서 10이 출력된다.
this.x역시 상속받은 멤버변수 x를 의미하므로 역시 10이 출력된다.
super.x는 조상의 멤버변수 x를 의미하므로 10이 출력된다.
사실 여기서는 자신의 멤버가 조상의 멤버와 중복되지 않기 때문에... super를 사용할 필요가 없다.
상속받은 멤버도 자신의 멤버이므로 this를 사용하는 것만으로도 충분하다.
예8)
public class SuperTest2 {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent {
int x = 10;
}
class Child extends Parent {
int x = 20;
void method() {
System.out.println("x=" + x);
System.out.println("this.x=" + this.x);
System.out.println("super.x=" + super.x);
}
}
Parent클래스가 있고...이 클래스를 상속받는 Child클래스가 있다.
Parent와 Child에 똑같이 멤버변수 x가 선언되어 있다.
조상의 멤버변수와 같은 이름의 인스턴스가 생성되면... 각각 별도의 저장공간을 차지하게 된다. 이름은 같아도 서로 다른 변수라는 것이다.
이 둘을 구별하기 위해서는 참조변수 super를 사용해야 한다. super를 붙이지 않으면... Child클래스의 멤버변수 x를 의미하게 된다.
Child인스턴스를 생성한 다음에... method()를 호출하면
x는 Child클래스의 멤버변수 x를 의미하므로 20이 출력되고. this.x역시 가까운 Child클래스의 멤버변수 x를 의미하므로 역시 20이 출력됩니다.
super.x는 조상인 Parent로 부터 상속받은 멤버변수 x를 의미하므로 10이 출력된다.
변수 만이 아니고 메서드 역시 super를 써서 호출할 수 있다. 특히 조상 클래스의 메서드를 자손 클래스에서 오버라이딩한 경우에 super를 사용한다.
class Point{
int x;
int y;
String getLocation(){
return "x:"+x+", y:"+y;
}
}
class Point3D extends Point{
int z;
String getLocation(){
//return "x:"+x+", y:"+y+", z:"+z;
return super.getLocation()+", z:"+z; //조상의 메서드 호출
}
}
getLocation()을 오버라이딩할 때 조상 클래스의 getLocation()을 호출하는 코드를 포함시켰다.
조상클래스의 메서드의 내용에 추가적으로 작업을 덧붙이는 경우라면 이처럼 super를 사용해서 조상클래스의 메서드를 포함시키는 것이 좋다. 후에 조상클래스의 메서드가 변경되더라도 변경된 내용이 자손클래스의 메서드에 자동적으로 반영될 것이기 때문이다.
super( )- 조상 클래스의 생성자
this()는 같은 클래스의 다른 생성자를 호출하는데 사용되지만,
super()는 조상 클래스의 생성자를 호출하는데 사용된다.
자손 클래스의 인스턴스를 생성하면, 자손의 멤버와 조상의 멤버가 모두 합쳐진 하나의 인스턴스가 생성된다.
그래서 자손 클래스의 인스턴스가 조상 클래스의 멤버들을 사용할 수 있는 것이다.
생성자의 첫 줄에서 조상클래스의 생성자를 호출해야하는 이유는 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수도 있으므로 조상의 멤버들이 먼저 초기화되어 있어야하기 때문이다.
아래처럼 자손의 생성자는 자기가 선언한 것만 초기화해야한다.
자손 클래스에서 조상 생성자를 호출할 때는 super()를 쓴다.
자손이 직접할 게 아니라 조상 생성자를 호출해서 초기화한다.
생성자의 첫 줄에 반드시 생성자를 호출해야한다.
->없으면 컴파일러가 첫 줄에 super()를 넣어줌
조상의 멤버는 조상의 생성자가 초기화
1. 클래스- 어떤 클래스의 인스턴스를 생성할 것인가?
2. 생성자- 선택하뉴 클래스의 어떤 생성자를 이용해서 인스턴스를 생성할 것인가?
예7)
public class PointTest {
public static void main(String[] args) {
Point3D p = new Point3D();
}
}
class Point{
int x,y;
Point(int x,int y){
this.x=x;
this.y=y;
}
String getLocation() {
return "x:"+x+", y:"+y;
}
class Point3D extends Point{
int z;
Point3D(int x, int y, int z){
this.x=x;
this.y=y;
this.z=z;
}
String getLocation() {
return "x:"+x+", y:"+y+",z:"+z;
}
}
}
-> 컴파일 에러 발생.
Point3D 클래스의 생성자에서 조상 클래스의 생성자인 Point()를 찾을 수 없다는 내용이다.
Point3D 클래스의 생성자의 첫 줄이 생성자(조상의 것이든 자신의 것이든) 를 호출하는 문장이 아니기 때문에 컴파일러는 자동적으로 'super();' 를 Point3D클래스의 생성자의 첫 줄에 넣어준다.
그래서 Point3D 클래스의 인스턴스를 생성하면, 생성자 Point3D(int x, int y, int z)가 호출되면서 첫 문장인 'super();'를 수행하게 된다. super() 는 Point3D클래스의 조상인 Point클래스의 기본 생성자인 Point()를 뜻하므로 Point()가 호출된다.
그러나 Point클래스에 생성자 Point()가 정의되어 있기 않기 때문에 위와 같은 컴파일 에러가 발생한 것이다.
-> 이 에러를 수정하려면, Point클래스에 생성자 Point() {}를 추가, Point3D 메서드에 super() 삽입
생성자 Point3D(int x, int y, int z)의 첫 줄에서 super(x, y)를 호출하도록 변경하면 된다.
조상 클래스의 멤버 변수는 이처럼 조상의 생성자에 의해 초기화되도록 해야한다.
예8)
public class PointTest2 {
public static void main(String[] args) {
Point3D p3 = new Point3D();
System.out.println("p3.x="+p3.x);
System.out.println("p3.y="+p3.y);
System.out.println("p3.z="+p3.z);
}
}
class Point{
int x=10;
int y=20;
Point(int x, int y){
super(); //생성자 첫 줄에서 다른 생성자를 호출하지 않았기에 컴파일러가 super(); 를 여기에 삽입한다.
this.x=x;
this.y=y;
}
}
class Point3D extends Point{
int z = 30;
Point3D(){
this(100, 200, 300);
}
Point3D(int x, int y, int z){
super(x, y);
this.z=z;
}
}
super()는 Point의 조상인 Object 클래스의 기본 생성자인 object()를 의미한다.
Point3D() -> Point3D(int x, int y, int z) ->Point(int x, int y) ->Object()
'JAVA > 객체지향프로그래밍2' 카테고리의 다른 글
[JAVA] 제어자(modifier) (0) | 2021.07.07 |
---|---|
[JAVA] import문 (0) | 2021.07.07 |
[JAVA] Object클래스 (0) | 2021.06.24 |
[JAVA] 단일 상속(single inheritance) (0) | 2021.06.24 |
[JAVA]포함(composite) (0) | 2021.06.24 |