티스토리 뷰

728x90
반응형

상속이란?


  • 자바에서 상속이란 부모 클래스에 정의된 필드와 메서드를 자식 클래스가 물려 받는것입니다.

 

상속의 장점


  • 클래스의 간결화 - 멤버 변수의 중복 작성 불필요
  • 클래스 관리 용이 - 클래스들을 계층적으로 분류
  • 클래스의 재사용성과 다형성

 

상속의 특징


  • 상속되는 클래스의 멤버 변수나 메서드를 선택적으로 상속받을 수 없습니다.
  • 상속을 받게 되면 super 클래스의 모든 속성과 기능을 상속받아 사용할 수 있습니다.
  • 생성자는 상속되지 않습니다.
  • 하나의 부모 클래스는 여러개의 자식 클래스를 가질 수 있습니다.
  • 자바의 최상위 클래스는 Object 클래스이며, 모든 클래스는 Object 클래스의 자식입니다.

 

super 키워드


  • 자바에서 자식 객체를 생성하면 부모 객체의 멤버 변수나 메소드를 사용할 수 있습니다. 그렇다면 자식 객체 생성 시 부모객체 생성이 되는가?
    • 위의 답은 그렇지 않습니다. 자식 객체 생성시 부모 객체가 먼저 생성된 뒤에 자식 객체가 생성됩니다.

`

public class Car {

    public Car() {
        System.out.println("부모 생성자 호출 : Car");
    }
}

public class SuperCar extends Car{

    public SuperCar() {
        System.out.println("자식 생성자 호출 : SuperCar");
    }
}

public class Example {
    public static void main(String[] args) {
        // 자식 생성자 객체 생성
        SuperCar superCar = new SuperCar();
    }
}

// 아웃풋
//부모 생성자 호출 : Car
//자식 생성자 호출 : SuperCar

 

  • super 키워드는 상속관계에서 부모 클래스의 멤버 변수나 메서드를 참조하기 위해서 사용됩니다. 
    • 자식 클래스에서 부모 클래스의 멤버 변수나 메서드를 오버라이딩한 경우 오버라이딩된 자식 메서드가 아닌  부모 클래스의 메서드를 사용하기 위해 사용됩니다.
  • 객체를 생성하기 위해서는 생성자가 필요합니다. 위의 예제에서는 부모객체를 따로 생성을 하지 않았는데 어떻게 생성이 된걸까요?
    • 이는 개발자가 따로 부모 객체의 생성자를 자식 클래스에 지정해 놓지 않는다면 컴파일러가 super() 메서드를 통해 부모의 기본 생성자를 호출합니다.
    • super()
  • 자식 클래스에서 부모 객체의 생성자를 호출하고 싶은 경우에도 위와 같은 방법으로 작성을 하면 됩니다.

 

 

자식 클래스에서 부모 클래스의 생성자를 선택하는 방법


Case 01 - 부모 클래스의 기본 생성자가 자동으로 선택되는 경우

  • 개발자가 명시적으로 부모 클래스의 생성자를 선택하지 않는 경우 컴파일러는 기본 생성자이든 매개변수를 가진 생성자이든 부모 클래스에서 기본 생성자가 선택됩니다.
  • SuperCar 클래스는 Car 클래스를 상속받고 있습니다. Car 클래스에는 2개의 생성자가 있지만 SuperCar의 기본 생성자가 호출되면 부모 클래스(Car)의 기본 생성자가 호출됩니다.
public class Car {
    private String name;

    public Car() {
        System.out.println("기본 부모 생성자 호출 : Car");
    }

    public Car(String name) {
        System.out.println("매개변수를 가진 부모 생성자 호출 값 : " + name);
    }
}

public class SuperCar extends Car{

    public SuperCar() {
        // 컴파일러가 super(); 코드를 생성하며 부모 클래스의 기본 생성자 호출
        System.out.println("기본 자식 생성자 호출 : SuperCar");
    }
}

public class Example {
    public static void main(String[] args) {
        // 자식 생성자 객체 생성
        SuperCar superCar = new SuperCar();
    }
}

// 아웃풋
// 기본 부모 생성자 호출 : Car
// 기본 자식 생성자 호출 : SuperCar

 

 

Case 02 - super()를 사용하여 명시적으로 부모 클래스의 생성자 선택

  • 자식 클래스의 생성자에서 super() 키워드를 사용하면, 부모 클래스의 생성자를 명시적으로 선택할 수 있습니다. super()는 부모 클래스의 생성자를 호출하는 코드입니다.
  • super()는 반드시 생성자의 첫 라인에 작성되어야 합니다.
public class Car {
    private String name;

    public Car() {
        System.out.println("기본 부모 생성자 호출 : Car");
    }

    public Car(String name) {
        System.out.println("매개변수를 가진 부모 생성자 호출 값 : " + name);
    }
}

public class SuperCar extends Car{

    public SuperCar() {
        // 기본 생성자 호출시 부모 클래스의 기본 생성자 호출
        System.out.println("기본 자식 생성자 호출 : SuperCar");
    }

    public SuperCar(String name) {
        // 매개변수 있는 생성자 호출시 부모 클래스에 메개변수가 일치하는 생성자 호출
        super("현대차");
        System.out.println("매개변수를 가진 자식 생성자 호출 : SuperCar");
    }
}

public class Example {
    public static void main(String[] args) {
        // 자식 생성자 객체 생성
        SuperCar superCar = new SuperCar("슈퍼카");
    }
}

// 아웃풋
// 매개변수를 가진 부모 생성자 호출 값 : 현대차
// 매개변수를 가진 자식 생성자 호출 : SuperCar

 

super.멤버 변수


  • 자식 클래스의 멤버변수와 부모 클래스의 멤버변수간 이름이 동일한 경우 부모 클래스의 멤버변수에 접근하는 경우 사용됩니다.

 

super.메서드


  • 자식 클래스의 메서드와 부모 클래스의 메서드간 이름이 동일한 경우 부모 클래스의 메서드에 접근하는 경우 사용됩니다.

 

상속시 주의 사항


  • 부모 클래스에 기본 생성자가 없고 매개변수가 있는 생성자가만 있다면 자식 클래스의 생성자 첫 라인에는 반드시 부모 클래스의 생성자를 명시적으로 호출해줘야 합니다. 그렇지 않으면 컴파일 에러가 발생하게 됩니다.
  • 아래 예제는 컴파일 오류가 발생하게 됩니다.
  • 문제가 발생하는 이유는 자식 클래스의 모든 생성자가 실행될 때 부모 클래스의 기본 생성자를 찾는데 부모 클래스에서는 기본 생성자가 없기 때문에 문제가 발생하고 있습니다.
  • 자바에서는 매개 변수가 있는 생성자를 만든 경우 컴파일러가 기본적으로 기본 생성자는 따로 만들어 주지 않습니다.
public class Car {
    private String name;

    public Car(String name) {
        System.out.println("매개변수를 가진 부모 생성자 호출 값 : " + name);
    }
}

public class SuperCar extends Car{
    private String name;

    public SuperCar() {
        System.out.println("기본 자식 생성자 호출 : SuperCar");
    }

    public SuperCar(String name) {
        System.out.println("매개변수를 가진 자식 생성자 호출 : SuperCar -> " + name);
    }
}

public class Example {
    public static void main(String[] args) {
        // 자식 생성자 객체 생성
        SuperCar superCar = new SuperCar("슈퍼카");
    }
}

 

생성자의 기본 전제


  • 개발자가 명시적으로 생성자를 만들지 않으면 컴파일러가 default 생성자를 생성하게 됩니다.
  • 그런데 만약 개발자가 매개변수가 있는 생성자를 만들게 되면 컴파일러는 default 생성자를 생성하지 않게 됩니다.
  • Car 클래스를 상속받은 SuperCar 클래스의 생성자를 호출하게 되면 개발자가 super(); 를 명시적으로 작성하지 않아도 super(); 라는 코드가 자동으로 삽입됩니다. 즉 Car 클래스의 default 생성자를 호출하게 됩니다.
    그런데 Car 클래스에서는 매개변수가 있는 생성자가 이미 선언되어 있기 때문에 default 생성자를 생성하지 않게 되는데 근데 super();는 매개 변수가 없는 기본 생성자를 호출하기 때문에 컴파일 에러가 발생하게 됩니다.

 

해결 방법


Case 01 - 부모 클래스의 default 생성자가 호출하지 않도록 명시적으로 작성해줍니다.

public class SuperCar extends Car{
    private String name;

    public SuperCar() {
        super("현대차");
        System.out.println("기본 자식 생성자 호출 : SuperCar");
    }

    public SuperCar(String name) {
        super("기아차");
        System.out.println("매개변수를 가진 자식 생성자 호출 : SuperCar -> " + name);
    }
}

 

Case 02 - 부모 클래스에 default 생성자를 명시적으로 작성해줍니다.

public class Car {
    private String name;

    // 명시적으로 기본 생성자 생성
    public Car() {
        System.out.println("기본 부모 생성자 호출 : Car");
    }

    public Car(String name) {
        System.out.println("매개변수를 가진 부모 생성자 호출 값 : " + name);
    }
}

 

 

메서드 오버라이딩


  • 상속은 extends 키워드를 사용하여 부모 클래스의 멤버변수나 메서드를 물려 받게됩니다. 이때 물려 받았으면 그 자체를 같은 방식으로 사용할 수 있지만 대부분 재정의하여 사용하는 경우가 많습니다. 이때 부모 클래스로부터 상속받은 메서드를 재정의하는 행위를 오버라이딩이라고 합니다.
  • 재정의를 하는경우 부모의 메서드는 은닉되고 자식의 메서드가 호출됩니다.
public class Car {

    public void myCarName(){
        System.out.println("소나타");
    }
}

public class SuperCar extends Car{

    @Override
    public void myCarName() {
        System.out.println("벤츠");
    }
}

public class Example {
    public static void main(String[] args) {
        SuperCar superCar = new SuperCar();
        superCar.myCarName(); // 벤츠
    }
}

 

 

오버라이딩 규칙


  • 부모 클래스의 메서드와 동일한 리턴타입과 이름, 매개변수를 가져야합니다.
  • 접근 제한자를 더 강하게 둘 수 없습니다.
    • 부모 메서드는 public이지만 자식이 private일 수 없습니다.(반대는 가능)
  • 새로운 예외를 throws할 수 없습니다.
728x90
반응형