Java에서 상속받을 경우 생성자 문제


자바에서 다음과 같이 Car클래스를 상속받는 Bus클래스를 만들었는데요. 실행하면 에러가 발생합니다.

class Solution {
  public static void main(String[] args) {
    Bus bus = new Bus("abc",1000,1000);
  }
}

class Car{
  String name;
  int number;
  public Car(String name, int number){
    this.name = name;
    this.number = number;
  }
}

class Bus extends Car{
  int fee;
  public Bus(String name, int number,int fee){
    this.name = name;
    this.number = number;
    this.fee = fee;
  }
}

public Bus(String name, int number,int fee){ ^ reason: actual and formal argument lists differ in length 1 error

Bus클래스를 다음과 같이 바꾸면 에러가 발생안하는데요.

class Bus extends Car{
  int fee;
  public Bus(String name, int number,int fee){
    super(name,number);
    this.fee = fee;
  }
}

원래 생성자에서 super를 안쓰는걸 허용 안하나요?

  • 2016년 02월 06일에 작성됨
    루비와 파이썬을 좋아합니다. 새로운 언어를 배우는것도 좋아해요. 모바일 게임도 조금 만들어 봤습니다.

조회수 526


1 답변


좋아요
2
싫어요
채택취소하기

Tod님이 작성한 코드에서는 반드시 super()를 호출해야합니다. 그 이유를 차근차근 설명해드릴게요.

처음에 아무것도 없는 Car클래스와 객체를 만든다고 합시다.(Tod님이 짜신 코드를 다 삭제하고 아무것도 없는 빈클래스부터 시작합니다.)

class Car {

}

Car car = new Car();

이렇게 보통 객체를 생성하지요. new라는 키워드로 객체를 생성할때 우리는 생성자를 호출하는것입니다.

new Car();<---생성자 호출

하지만 Car라는 클래스에는 생성자가 보이지 않죠. 생성자를 본인이 직접 만들수도 있지만 생성자를 만들지 않으면 컴파일러에서 알아서 만들어줍니다.

컴파일러에서 만드는 기본 생성자는 아래와 같습니다.

public Car {

}

여기에 본인이 생성자를 오버로딩을 해서 구현을 한다면 컴파일러에서는 생성자를 자동으로 만들어주지 않습니다.

class Car{
  String name;
  int number;
  public Car(String name, int number){
    this.name = name;
    this.number = number;
  }
}

이렇게 Tod님이 만드신 생성자가 들어갔으므로 Car()라는 기본생성자는 만들어지지 않습니다. 그래서 Car car = new Car();이렇게 호출이 불가능한것입니다. 생성자 오버로딩코드를 지우고 다시 원래 클래스로 돌아가봅니다. 이제 Car라는 클래스를 상속받아 Bus라는 클래스를 만듭니다.

class Car {

}
class Bus extends Car {

}

여기서 Bus객체를 만들면 어떻게 될까요? Bus bus = new Bus();이렇게 Bus의 생성자를 호출하면 Car의 생성자를 호출하고 Object클래스의 생성자까지 호출되게 됩니다. (자바에서는 보이진 않지만 모두 Object라는 클래스를 다 상속받고 있어요.) 이러한 과정을 Constructur chaining이라고 합니다. Bus를 생성할때 힙에는 Bus만 생기는 것이 아니라 Car가 가지고 있는 정보도 모두 들어 있습니다. 두 클래스에 들어있는 모든 인스턴스 변수가 힙 안에 들어가죠.


public class Car {
    public Car(){
        System.out.println("Making an Car");
    }
}

public class Bus extends Car {
    public Bus() {
        System.out.println("Making an Bus");
    }
}

Sytem.out.println()으로 출력문 결과를 보면 Car가 먼저 출력되고 Bus가 나중에 출력됩니다. 컴파일러에서 자동으로 super()를 호출하기 때문에 Car가 출력된것입니다.

생성자를 만들긴 했는데 super()를 호출하지 않은 경우에는 컴파일러에서 모든 생성자에 super()를 호출하는 코드를 자동으로 추가해줍니다. 생성자에서 다른 오버로드된 생성자를 호출하지 않는 경우에만 그렇습니다. 컴파일러에서 상위클래스 생성자를 호출하는 선언문을 자동으로 추가할 때는 인자가 없는 형태의 생성자super(); 를 사용합니다.

이제 여기에 Tod 님이 만든 인자가 들어있는 생성자코드를 추가해봅니다.

class Car {
    String name;
    int number;

    public Car(String name, int number){
        this.name = name;
        this.number = number;
        System.out.println("CAR 2");
    }
}

class Bus extends Car {

    int fee;

    public Bus(String name, int number, int fee) {
        this.name = name;
        this.number = number;
        this.fee = fee;
    }
}


Bus bus = new Bus("서울", 1004, 2000);

이렇게 생성자를 호출해서 객체를 만들면 컴파일러에서는 자동으로 super();를 호출합니다. 부모를 먼저 만들려고 시도하나 부모인 Car클래스에는 Car();라는 생성자가 없습니다. 생성자가 하나도 없는 경우에만 컴파일러에서는 public Car(){}라는 생성자를 자동으로 만들어줍니다. Car라는 클래스에 public Car(){} 생성자를 작성해주면 에러가 나지 않습니다.

class Car {
    String name;
    int number;

    public Car(){

    }
    public Car(String name, int number){
        this.name = name;
        this.number = number;
        System.out.println("CAR 2");
    }
}

이렇게 인자가 없는 생성자를 하나 추가해주거나, Bus클래스에서 Car의 생성자 public Car(String name, int number) 를 호출해주어야만 에러가 발생하지 않습니다.

새로운 하위클래스 객체가 생기기전에는 항상 그 객체의 상위클래스가 먼저 생성되어야합니다. 간단하게 이렇게 생각하세요. 항상 부모가 먼저 만들어집니다. 부모는 자식보다 먼저 태어납니다. :)

  • 2016년 06월 01일에 수정됨
    안드로이드, 루비온레일즈
  • 2016년 02월 06일에 작성됨
    안드로이드, 루비온레일즈

로그인이 필요한 기능입니다.

Hashcode는 개발자들을 위한 무료 QnA사이트 입니다. 작성한 답변에 다른 개발자들이 댓글을 작성하거나 좋아요/싫어요를 할 수 있기 때문에 계정을 필요로 합니다.
► 로그인
► 계정만들기
Close