[Java] 참조변수 super, 생성자 super()

준우·2023년 2월 18일
0

Java

목록 보기
28/30
post-thumbnail

참조변수 super

  • 객체 자신을 가리키는 참조변수
  • 인스턴스 메서드(생성자) 내에만 존재
  • 조상의 멤버를 자신의 멤버와 구별할 때 사용

    로컬 변수와 인스턴스 변수를 구분할 때 사용하는 참조변수 this와 유사하다.

예시 코드 (1)

class Ex7_2 {
	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); 			 //x=20
		System.out.println("this.x=" + this.x);  //this.x=20
		System.out.println("super.x="+ super.x); //super.x=10
	}
}

변수의 이름이 같아도 실행이 된다.
다만 this 혹은 super 키워드를 붙이지 않는 경우 가까운 쪽의 변수 값이 지정된다.
this 키워드를 붙이면 자신의 멤버를, super 키워드를 붙이면 조상의 멤버를 가져온다.

예시 코드 (2)

class Ex7_3 {
	public static void main(String args[]) {
		Child2 c = new Child2();
		c.method();
	}
}

class Parent2 { 
	int x=10; 
}

class Child2 extends Parent2 {
	void method() {
		System.out.println("x=" + x);
		System.out.println("this.x=" + this.x);
		System.out.println("super.x="+ super.x);
	}
}

위 코드의 경우 Child2 클래스에는 x라는 값이 없다.
그래서 xthis.x, super.x 모두 Parent2 클래스의 x이다.
중복되지 않는 경우 this.x 임과 동시에 super.x인 것이다.

생성자 super()

  • 조상의 생성자를 호출할 때 사용한다.
  • 조상의 멤버는 조상의 생성자가 초기화 하도록 한다.
    다른 말로, 조상의 멤버는 조상의 생성자를 호출해서 초기화 한다.

상속을 해도 조상 클래스의 생성자와 초기화 블럭은 상속되지 않음을 유의한다.

"조상의 멤버는 조상의 생성자가 초기화 하도록 한다." 가 무슨 말이냐면,아래와 같은 두개 클래스가 있다고 할 때
Point 클래스의 멤버(조상의 멤버)는 자식 클래스가 정의하는 것이 아니라, 조상의 생성자를 super()로 호출해서 초기화 해야한다는 것이다.

부모 클래스

class Point {
	int x, y;
    
    Point(int x, int y){
    	this.x = x;
        this.y = y;
	}
}

자식 클래스

class Point3D extends Point {
	int z;
    
    //BAD
    /*
    Point3D(int x, int y, int z){
    	this.x = x;
        this.y = y;
        this.z = z;
	}
    */
    
    //Good
    Point3D(int x, int y, int z){
    	super(x, y);
        this.z = z;
	}
    
}

주의점

  • 생성자의 첫줄에 반드시 생성자(this(), super())를 호출해야 한다.
    그렇지 않으면 컴파일러가 생성자의 첫줄에 super();를 삽입한다.

생성자 조건

  • 생성자를 하나라도 만들지 않으면 자바는 기본 생성자를 만들어준다.
class Point {
	int x;
    int y;
    
    Point() {
    	this(0, 0);
    }
    
    Point(int x, int y) {
    	this.x = x;
        this.y = y;
    }
}

위 Point 클래스는 사실 아래 코드처럼
최상위 Object 클래스의 상속과 super(); 삽입이 생략되어있는 구조이다.

class Point extends Object {
	int x;
    int y;
    
    Point() {
    	this(0, 0);
    }
    
    Point(int x, int y) {
    	super(); 		//Object();
    	this.x = x;
        this.y = y;
    }
}

예시 코드

class Point {
	int x;
    int 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;  
    }
}
class PointTest {
	public static void main(String args[]) {
    	Point3D p3 = new Point3D(1, 2, 3);
    }
}

위와 같이 상속 관계를 가진 두 클래스가 있을 때, Point3D의 생성자를 호출하는 메인 메서드를 실행하면 컴파일러 에러가 발생한다.

왜냐하면 위에서 설명한 생성자 조건에 따라 Point3D 클래스에서는 생성자 첫 줄에 생성자를 호출하지 않아서 컴파일러가 자동으로 super()를 호출 했는데, Point 클래스에서는 이미 하나 이상의 생성자가 선언되었기에 기본 생성자 Point()가 자동 생성되지 않아 Point() 생성자를 찾을 수 없다는 컴파일러 오류가 나는 것이다.

생략된 코드를 명시하면 아래와 같다.

class Point {
	int x;
    int y;
    
    Point(int x, int y) {
    	super(); //object();
    	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) {
    	super(); //point()를 호출 -> 그런데 Point()가 없어서 오류 발생
    	this.x = x;
        this.y = y;
        this.z = z;
    }
    
    //오버라이딩
    String getLocation(){
		return "x: " + x + ", y: " + y + ", z:" + z;  
    }
}
class PointTest {
	public static void main(String args[]) {
    	Point3D p3 = new Point3D(1, 2, 3);
    }
}

그러니 에러를 해결하기 위해서 Point클래스에서 기본 생성자를 선언하거나, Point3D 클래스에서 조상의 생성자를 아래처럼 호출해야한다. 전자도 오류가 발생하지는 않겠지만, 올바른 코드는 후자이다. 조상의 멤버는 조상의 생성자를 호출해서 초기화해야하기 때문이다.

Point3D(int x, int y, int z) {
	//조상의 생성자 Point(int x, int y)를 호출
    super(x, y);
    this.z = z;
}

🫡 Reference

0개의 댓글