반응형

1. 개요

 자주 쓰는 상속과 생성자의 개념에 대해 간단히 정리하고, 상속관계에서 발생할 수 있는 문제에 대해 알아보자.


2. 상속이란?

 상속이란 부모님에게 재산을 물려받듯이 부모 클래스의 멤버필드와 메서드를 자식클래스가 물려받는 것이다.

 상속을 통해 불필요한 중복을 제거할 수 있다.


3. 생성자란?

 객체에 대한 초기화 메서드이다. 멤버 변수를 초기화하거나 자원을 할당할 수 있다.

 클래스 내 생성자가 정의되어 있지 않을 경우 자바가 자동으로 no-parameter 생성자를 생성한다.

 

 여기까지가 많은 사람들이 알고 있는 생성자에 대한 간단한 정의이다. 하지만 다음과같은 내용도 있다.

더보기

 자식클래스의 생성자는 부모클래스의 생성자를 먼저 호출한다.

 명시적으로 호출하지 않을 경우 부모클래스의 no-parameter 생성자가 자동적으로 호출된다.

별게 아닌 것 같지만, 이 내용을 알지 못했을 때 발생할 수 있는 문제 상황이 있다. 한번 알아보자.


4. 상속, 생성자 예제

 상속 관계로 부모 클래스는 술(Alcohol), 자식 클래스는 럼(Rum)으로 하겠다. (럼: 해적들이 마시던 술)

 

4.1. Alcohol.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Alcohol {
 
    protected double frequency;
    protected double price;
    protected String flavor;
    
    public Alcohol(double frequency, double price, String flavor) {
        this.frequency = frequency;
        this.price = price;
        this.flavor = flavor;
    }
    
    public String whatFlavor() {
        return "flavor is "+flavor;
    }
}
cs

모든 술에는 도수, 가격, 맛이 존재한다. 그에 맞게 frequency, price, flavor 멤버필드를 선언해주었고, 모든 멤버필드의 값을 초기화해주는 생성자도 생성하였다. 추가적으로 whatFlavor라는 간단한 메서드도 정의하였다.

 

4.2. Rum.java

1
2
3
4
5
6
7
8
9
10
11
public class Rum extends Alcohol{
 
    private String rumType;
 
    public Rum(String rumType, double frequency, double price, String flavor) {
        this.rumType = rumType;
        this.frequency = frequency;
        this.price = price;
        this.flavor = flavor;
    }
}
cs

Alcohol 클래스를 상속받는 Rum 클래스를 정의하였다.

Alcohol 클래스를 상속받았기때문에 이에 대한 멤버필드와 메서드를 Rum 클래스에서 할당받게 된다. 즉, Rum 클래스의 멤버필드는 rumType, frequency, price, flavor가 된다. 마찬가지로 Rum 클래스의 생성자도 정의하였다.

...

...

...

혹시 이 예제에서 문제점을 발견했는가? 발견했다면 당신은 멋진사람...

 

4.3. 컴파일 에러

 이 예제는 언뜻보면 이상이 없어보이나 다음과 같이 컴파일 에러가 발생하는 코드이다.

컴파일 에러

 에러 내용은 다음과 같다. 

더보기

 Implicit super constructor Alcohol() is undefined.

 암시 적 슈퍼 생성자 Alcohol ()이 정의되지 않았습니다.

 바로 이게 앞서 언급했던 "자식클래스의 생성자는 부모클래스의 생성자를 먼저 호출한다." , "명시적으로 호출하지 않을 경우 부모클래스의 no-parameter 생성자가 자동적으로 호출된다." 라는 생성자의 정의에 의해 발생한 에러이다.

 

 자식클래스의 생성자는 호출 전에 부모클래스의 생성자를 호출해야하는데, 현재 Rum 생성자를 보면 알수있듯이 부모 클래스의 생성자를 호출하는 메서드인 super(...)가 없다. 즉, 명시적으로 호출하지 않았기 때문에 자바가 Rum 생성자 내에서 부모 클래스의 no-parameter 생성자를 자동적으로 호출하려했으나 현재 부모클래스에는 no-parameter 생성자가 없기 때문에 위 에러가 발생한 것이다.

 

그렇다면 해결은 어떻게 할까?


5. 해결

이를 해결하기 위해서는 두가지 방법이 있다.

첫번째, 부모클래스에 no-parameter 생성자를 생성한다.

두번째, 자식클래스의 생성자에 부모클래스의 생성자를 명시적으로 호출한다.

첫번째 방법은 에러 제거만을 목적으로 불필요한 코드를 추가하기 때문에 추천하지 않는 방법이다. 자식 클래스 생성자 내에서 부모 클래스의 생성자를 명시적으로 호출하는 두번째 방법을 사용하자.

 

5.1. Rum.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class Rum extends Alcohol{
 
    private String rumType;
 
    public Rum(String rumType, double frequency, double price, String flavor) {
        super(frequency, price, flavor);
        this.rumType = rumType;
    }
    
    public static void main(String[] args) {
        Rum rum = new Rum("DarkRum"40.069000"bitter");
        System.out.println(rum.whatFlavor());
    }
}
cs

Rum 생성자 안에서 super() 메서드를 통해 부모 클래스의 생성자를 명시적으로 호출해주고, 부모클래스에 없는 rumType은 this를 통해 초기화하였다.

 

main 메서드에서 생성자를 통해 Rum 객체를 생성하여 테스트하면 정상적으로 작동됨을 확인할 수 있다.

 

 

오늘 자료구조를 공부하며 알게 된 새로운 내용을 정리할 수 있어 기쁘다.

반응형

+ Recent posts