본문 바로가기
교육, 학습/멀티캠퍼스_풀 스택

JAVA 문법 - super 와 super() 비교, super를 활용한 메서드 오버 라이딩

by 개발하는 경제학도 2022. 1. 6.

강의 소개

현재 수강하고 있는 멀티캠퍼스 k-digital 지능형 웹서비스 풀 스택 과정을 수강하며 적은 내용입니다.

교재로는 자바의 정석을 사용하고 있습니다.


 

super

this는 자기 자신을 지칭하는 키워드인데, 반면 super키워드는 상속하는 부모 객체를 지칭한다.

이때, super와 super()는 활용에 있어 차이가 있어 비교해본다.

 

1.  super.

super는 부모 클래스로부터 상속받은 메서드 혹은 필드를 자식 클래스가 참조할 때 사용하는 참조 변수이다.

 

- 특징

부모 클래스의 멤버(필드, 메서드)가 자식 클래스의 멤버와 같을 경우 super로 부모 클래스를 지칭하여 구분할 수 있다.

super 참조 변수를 사용할 수 있는 대상은 인스턴스 메서드뿐이며, 클래스 메서드(= static 메서드)에는 사용하지 못한다.

(this 키워드도 동일하다)

'super. 메서드()'를 통해 자식 클래스에서 메서드 오버 라이딩이 가능하다. (예시 2번에서 다룬다)

 

- 예시

[예시 1. 부모 변수(필드) 호출]

// 부모 클래스
public class Parent {
	int x = 1;
}

// 자식 클래스
public class Child extends Parent {
	int x = 2;
    
    void result() {

        System.out.println(x);  // 2
        System.out.println(this.x); // 2
        System.out.println(super.x); // 1
}

// 실행(메인메서드)
public static void main(String args[]) {
	Child child = new Child();
    child.result();
}

부모 클래스를 상속받은 자식 클래스(여기선 Child 클래스)에서 아래와 같은 결과를 보여준다.

지역변수(그냥 x)와 this 참조 변수(this.x)는 자식 클래스 본인의 값이,

super 참조 변수(super.x)는 부모 클래스의 값이 출력된다.

따라서 부모 클래스의 멤버를 호출하고자 할 때는 super.로 해야 호출할 수 있는 것이다.

 

[예시 2. 부모 메서드 호출을 통한 오버 라이딩]

public class Person {
	public String 자기소개() {
    	return "사람입니다." 
    }
    
pubic class Employee extends Person {
	public String 자기소개() {
		return super.자기소개() + " 그리고 직원입니다"
	}
}

자식 클래스에서 'super. 메서드()'를 사용하여 부모 클래스의 메서드를 호출할 수 있다.

특히, 위의 예제에서는 부모 클래스의 메서드를 단순 호출하는 것을 넘어,

자식 클래스에서 super. 메서드()를 사용하여 자기소개 메서드를 오버 라이딩(= 메서드 재정의)했다.

이렇게 'super. 메서드()'를 사용하여 오버 라이딩하면 좋은 점이 있다. 첫 번째로 코드의 재사용성이며 두 번째로는 후에 부모 클래스의 메서드가 변경되더라도 자식 클래스에도 그 변경사항이 자동으로 반영되는 것이다.

 


 

2.  super()

super()는 부모 생성자를 호출할 때 사용한다.

 

- 특징

자바는 상속 관계인 클래스에서는 자식 클래스에서 맨 첫 문장에 자동적으로 super()를 호출한다.

super() 혹은 this()는 생성자의 {구현부} 첫 문장에 반드시 쓰여야 한다.

이 super()는 사용자가 작성하지 않아 보이지 않더라도 컴파일러에 의해 자동적으로 삽입되어 실행된다.

이 super()를 실행하게 되면, 부모 객체가 생성되며, 부모 클래스의 모든 조상 클래스들의 객체들도 생성된다.

따라서 최종적으로는 **Object 객체까지 만들어지는 것이다.

 

(Object 클래스 자세히)

더보기

** Object 클래스

자바 내 모든 클래스의 최고 조상이다.

부모 없는 자식이 없듯, 모든 클래스들은 Object클래스를 자동적으로 상속받았다. Object를 제외한 모든 클래스들은 부모 클래스가 있다.

 

결론적으로 super()를 호출하게 되면 '부모 객체 생성 -> 부모의 부모 객체 생성 ->.. -> Object 객체 생성'으로 상속관계를 모두 거슬러 올라가며 객체를 생성한다. 

그 이유는 자식 클래스의 객체(인스턴스)가 부모 클래스의 멤버(필드, 메서드)를 사용할 수도 있기 때문에 부모 클래스들의 멤버들이 먼저 초기화해서 준비해두는 것이다.

 

- 예시

[예시 1. 기본 생성자 부모 생성자 호출: super()]

public Employee() {
	// super();  //이 라인은 직접 적지 않아도 들어가있으며, 이 라인을 생략해도 super()를 사용한 부모의 생성자 호출은 실행된다.
    System.out.println("Employee 생성자 실행")
}

super()은 기본 생성자이다. 따라서 (Object 클래스 객체를 제외한) 모든 클래스의 첫 라인에 컴파일에 의해 자동으로 생성되어 있다.

 

[예시 2. 매개변수가 있는 부모 생성자 호출: super(매개변수)]

class A {
	int i;
	A(String s) {
		System.out.println("A생성자 호출");
		i = 10;
	}
}

class B extends A {
	int j;
	B() {
		// super();  // 생성자의 가장 첫 줄은 super()가 있는 것이다 : 상위클래스의 생성자가 항상 먼저 호출된다. 자동으로. (사실은 Object 객체 생성 -> 상위클래스 객체 생성 -> 하위클래스 객체 생성 순으로 생성된다)
		this("전달");
		System.out.println("B생성자 호출");
		j = 100;
	}
	B(String s) {
		super(s); // this, super는 모두 첫 문장에 있어야 해서 만들어진 코드 
	}
}

public class SuperTest {

	public static void main(String[] args) {
		B b1 = new B(); 
        // A생성자 호출
        // B생성자 호출
		System.out.println(b1.i); // 10
		System.out.println(b1.j); // 100 
	}

}

출력 결과는 아래와 같다.

A생성자 호출
B생성자 호출
10
100

B의 기본 생성자 호출 -> this("전달")로 B(String s) 생성자 호출 -> super(s)로 A(String s) 생성자 호출 -> "A생성자 호출 출력" -> A생성자가 호출되어 인스턴스가 생성되었으므로 자식 생성자인 B() 생성자 호출 & 출력

그래서 "A생성자 호출"이 먼저 출력된 후 "B 생성자 호출"이 출력된 것이다.

위의 예제는 복잡해 보이지만 간단한 경우에는 자식 생성자 B가 super()를 사용하여 A생성자를 호출하고 싶었으나, 부모 클래스인 클래스 A에 기본 생성자가 없기 때문에 조금 더 복잡한 예제가 되었다.

(Ex. 만약 클래스 A에 기본 생성자로 A()가 있거나, 아니면 클래스 A에 아예 생성자가 없었다면 컴파일러가 자동으로 기본 생성자를 만들어주었을 것이다. 이런 경우 클래스 B의 첫 문장에 super()만 사용하면 되어서 간단한 예제가 되었을 것이다)

 

(생성자 자세히)

2022.01.04 - [교육, 학습/멀티캠퍼스_풀 스택] - JAVA 문법 - 상속, 생성자 개념과 비교, 주의점(is - a, has - a)

 

[예시 3. 간단한 ver) 매개변수가 있는 부모 생성자 호출: super(매개변수)]

class Parent {

    int a;
    
	// 기본 생성자: 매개변수가 없다 
    Parent() { 
    	a = 10; 
    }

	// 매개변수가 있는 생성자
    Parent(int n) { 
    	a = n; 
    }
}

 
class Child extends Parent {

    int b;

    Child() {
        super(); // 부모 클래스의 기본 생성자 호출
        b = 20;
    }
}

매개변수를 가지는 생성자를 선언해야 할 경우에는 위처럼 기본 생성자까지 명시적으로 선언하는 것이 좋다.

 

 

출처: 자바의 정석(남궁 성 저), 멀티캠퍼스

댓글