1. super란?
super는 자손 클래스에서 조상 클래스로부터 상속받은 멤버를 참조하는데 사용하는 참조변수입니다. 조상의 멤버와 자신의 멤버를 구별하는데 사용되다는 점을 제외하고는 super와 this는 근본적으로 같습니다. 모든 인스턴스메서드에는 자신이 속한 인스턴스의 주소가 지역변수로 저장되는데, 이것이 참조변수인 this와 super의 값이 됩니다.
2. 사용 이유
상속받은 멤버와 자신의 멤버와 이름이 같을 때 super를 붙여서 구별할 수 있습니다. 조상 클래스에 선언된 멤버변수와 같은 이름의 멤버변수를 자손 클래스에서 중복해서 정의하는 것이 가능하기 때문에 필요한 기능입니다. 멤버변수와 지역변수의 이름이 같은 때 this를 붙여서 구별하는 것과 유사합니다.
3. 사용 방법
public class SuperTest {
public static void main(String[] args) {
Child c = new Child();
c.method();
}
}
class Parent{
int x =10;
}
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);
}
}
//결과
//x=10
//this.x=10
//super.x=10
위 예제에서 볼 수 있듯이 조상 클래스부터 상속받은 멤버도 자손 클래스 자신의 멤버이므로 super대신 this를 사용할 수 있지만, 조상 클래스의 멤버와 자손클래스의 멤버가 중복 정의되어 서로 구별해야하는 경우에만 super를 사용하는 것이 좋습니다. 아래 예제를 보면,
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);
}
}
//결과
//x=20
//this.x=20
//super.x=10
이전 예제와 달리 같은 이름의 멤버변수가 조상 클래스인 Parent에도 있고 자손 클래스인 Child클래스에도 있을 때는 super.x와 this.x는 서로 다른 값을 참조하게 됩니다. super.x는 조상 클래스로부터 상속받은 멤버변수 x를 뜻하며, this.x는 자손 클래스에 선언된 멤버변수를 뜻합니다.
변수만이 아니라 메서드 역시 역시 super를 써서 호출할 수 있습니다. 특히 조상 클래스의 메서드를 자손 클래스에서 오버라이딩한 경우에 super를 사용합니다. 아래 예제 처럼 조상클래스의 메서드의 내용에 추가적으로 작업을 덧붙이는 경우라면 이처럼 super를 사용해서 조상클래스의 메서드를 포함하는 것이 좋습니다!
그 이유는 후에 조상클래스의 메서드가 변경되더라도 변경된 내용이 자손클래스의 메서드에 자동적으로 반영될 것이기 때문입니다.
public class Point {
int x,y;
String getLocation() {return "x :" + x + ", y:"+y;}
}
class Point3D extends Point{
int z;
String getLocation() { //오버라이
return super.getLocation() + ", z :" + z; //조상의 메서드 호
}
}
3.1 제약사항
static메서드(클래스메서드)는 인스턴스와 관련이 없습니다. this와 마찬가지로 super역시 static메서드에서는 사용할 수 없고, 인스턴스메서드에서만 사용할 수 있습니다.
3.2 super - 조상 클래스의 생성자
super()는 조상 클래스의 생성자를 호출합니다. 자손 클래스의 인스턴스를 생성하면 자손의 멤버와 조상의 멤버가 모두 합쳐진 하나의 인스턴스가 생성됩니다. 그래서 자손 클래스의 인스턴스가 조상 클래스의 멤버들을 사용할 수 있습니다. 이때 조상 클래스 멤버의 초기화 작업이 수행되어야 하기 때문에 자손 클래스의 생성자에서 조상 클래스의 생성자가 호출되어야 합니다.
Object클래스를 제외한 모든 클래스의 생성자는 첫 줄에 자신의 다른 생성자 또는 조상 클래스의 생성자를 호출해야 합니다. 그렇지 않으면 생성자는 첫 줄에 'super();'를 자동적으로 추가합니다. 생성자의 첫 줄에서 조상클래스를 호출하는 이유는 자손 클래스의 멤버가 조상 클래스의 멤버를 사용할 수도 있으므로 조상의 멤버들이 먼저 초기화되어 있어야 하기 때문입다.
조상 클래스 생성자의 호출은 클래스의 상속관계를 거슬러 올라가면서 계속 반복됩니다. 마지막으로 모든 클래스의 최고 조상인 Object클래스의 생성자인 Object()까지 가서야 끝이 납니다.
아래 예제를 실행하면,
public class PointTest{
public static void main(String []args){
Point3D p3 = new Point3D(1,2,3);
}
}
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;
}
}
다음과 같이 컴파일 에러가 발생합니다.
PointTest.java:23: error: constructor Point in class Point cannot be applied to given types; Point3D(int x, int y, int z){ ^ required: int,int found: no arguments reason: actual and formal argument lists differ in length 1 error
Point3D클래스의 생성자에서 조상 클래스의 생성자인 Point()를 찾을 수 없다는 내용입니다. Point3D 생성자의 첫 줄이 생성자(조상의 것 또는 자신의 것)를 호출하고 있지 않기 때문에 컴파일러는 자동적으로 첫 줄에 'super();'를 삽입합니다. 하지만 Point클래스에서 기본 생성자인 Point()가 정의 되어 있지 않기 때문에 컴파일 에러가 발생한 것입니다. 해당 에러를 수정하기 위해서는 Point3D 생성자 첫 줄에 Point(int x, int y)를 호출하도록 변경하면 됩니다.
Point3D(int x, int y, int z){
super(x,y); //Point(int x, int y)를 호출한다.
this.z = z;
}
'Point3D p3 = new Point3D()' 인스턴스를 생성하면 다음과 같은 순서로 생성자가 호출됩니다.
Point3D() -> Point3D(int x, int y, int z) -> Point(int x, int y) -> Object()
출처
https://javaforbeginnerstutorial.blogspot.com/2015/09/super-keyword-in-java.html
'자바' 카테고리의 다른 글
[Java] 자바의 제어문2, 조건문 (2) | 2020.12.12 |
---|---|
[Java] 자바의 제어문1, 반복문 (0) | 2020.12.12 |
[Java] 람다(Lambda)와 java.util.function패키지 (0) | 2020.04.17 |
[Java] 람다(Lambda) (0) | 2020.04.14 |
[Java] Java의 탄생 (0) | 2019.03.28 |
댓글