3. 상속

상속 개념

부모 클래스의 멤버(필드, 메소드)를 자식 클래스에게 물려주는 것

상속의 장점

  • 공통 속성을 가진 클래스를 빠르게 작성하도록 도와줌

  • 부모 클래스 수정으로 자식 클래스의 수정 효과도 가져오기 때문에 유지보수 시간을 최소화

  • 다형성의 적극적 이용 가능

멤버가 상속되지 않는 경우

  • 부모 클래스에서 private 접근 제한자를 갖는 필드, 메소드는 상속 대상에서 제외된다.

  • 부모 클래스와 자식 클래스가 다른 패키지에 존재한다면, default 접근 제한을 갖는 필드와 메소드도 상속 대상에서 제외된다.

다중 상속

  • 기본적으로 허용 안함

  • 인터페이스는 다중 상속이 됨

상속의 부모 생성자 호출

  • 부모 객체를 상속하는 자식 객체가 생성될 때, 부모 생성자를 호출하며 메모리 상에도 부모 객체가 존재함

  • 자식 객체는 생성된 부모 객체를 참조함

  • 자식 생성자의 맨 첫줄에서 부모 생성자가 자동적으로 호출됨

    • 부모 클래스에 기본 생성자가 없다면, super() 메소드를 이용해 호출해주어야 함

      • 부모 생성자가 호출되지 않을 시에 컴파일 에러가 남

메소드 재정의 (@Override)

  • 상속받은 메소드가 자식 클래스에서 사용하기 적절하지 않다고 판단할 때, 부모 메소드의 시그니처를 그대로 물려받아 동일한 메소드를 재정의할 수 있음

메소드 재정의 (오버라이딩) 의 규칙

  • 부모 메소드와 동일한 시그니처(리턴 타입, 메소드 이름, 매개변수 리스트)를 가져야 한다.

  • 접근 제한을 더 강하게 오버라이딩할 수 없다. (public -> private)

  • 새로운 예외(Exception)를 throws할 수 없다.

@Override 애노테이션

  • 부모 메소드의 시그니처를 올바르게 물려받았는지 검사하고 그렇지 않을 시에 컴파일 에러를 낸다.

상속 시 부모 메소드의 호출

  • super 키워드를 이용해서 가능하다.

super.method1(); // 부모 클래스에 method1()이 있다고 가정

final 클래스와 final 메소드의 상속

final 클래스의 상속

  • final 클래스는 상속이 불가능하다. 부모 클래스가 될 수 없다.

final 메소드의 상속

  • final 메소드는 오버라이딩할 수 없다.

  • final 필드나 메소드의 원형으로는 사용하는데 문제 없다.

protected 접근 제한자

  • protected는 필드, 생성자, 메소드에 적용할 수 있다.

  • 다른 패키지에 소속된 클래스에서는 접근할 수 없다. (default와 같음)

    • 단, 다른 패키지여도 자식 클래스에서는 접근 가능하다.

타입 변환과 다형성

  • 다형성을 위해 자바는 부모 클래스로 타입 변환을 허용한다.

  • 모든 자식은 부모 객체로 타입 변환할 수 있다.

    • 이것을 응용하면 상위 타입에 대해 다양한 하위 타입을 적용하여 다형성을 이용할 수 있다.

자동 타입 변환

  • 부모 클래스 변수 타입에 자식 클래스 변수를 할당하면 자식에서 부모로 자동으로 타입이 변환된다.

  • 변수 뿐 아니라, 상위 타입의 파라미터에도 하위 타입의 인자를 넣으면 자동적으로 상위 타입으로 타입이 변환된다.

  • 바로 위의 부모가 아니어도 하위 타입이기만 하면, 자동 타입 변환은 적용된다.

  • 자동 타입 변환된 부모 클래스에서 자식 클래스에 의해 오버라이드된 메소드를 호출하면, 오버라이드된 메소드가 호출된다.

    • 다형성(Polymorphism)과 관련이 있기 때문에 매우 중요하다.

강제 타입 변환

  • 자식 클래스에서 부모 클래스로 자동 타입 변환이 일어났던 객체를 다시 강제 타입 변환을 이용하여 자식 클래스로 돌릴 수 있다.

    • 자식 클래스에 선언된 메소드를 반드시 사용해야 한다면 강제 타입 변환을 이용하면 된다.

객체 타입 확인(instanceof)

지금 다루는 객체가 자동 타입 변환이 되어 부모 클래스가 된 것인지 아니면 처음부터 부모 클래스로 생성되었는지 궁금할 수 있다. 이럴 때, instanceof를 사용하여 이 객체의 타입을 확인할 수 있다.

객체명 instanceof 타입명

public void isAutoTypeCastedClass(Parent parent) {
  if(parent instanceof Child) {
    System.out.println("Child 클래스로부터 자동 타입 변환된 클래스입니다. Child 클래스로 강제 타입 변환 가능합니다.");
  } else {
    System.out.println("Child 클래스로부터 자동 타입 변환된 클래스가 아닙니다.");
  }
}

추상 클래스

추상 클래스는 객체로 실체화할 수는 없지만, 특정한 객체들의 공통적인 부분을 모아놓은 클래스이다. 여기서 특성은 필드와 메소드를 말한다. 추상 클래스는 인스턴스를 생성할 수 없지만, 특정 클래스의 부모 클래스로서 활용된다.

추상 클래스의 구체적 용도

  • 실체 클래스들의 공통된 필드와 메소드의 이름을 통일할 목적

  • 실체 클래스를 작성할 때 시간을 절약

    • 공통적인 특성을 갖는 추상 클래스를 부모로 상속하면 중복 코드가 적어져 시간이 절약된다.

    • 설계 단계에서 추상 클래스를 미리 설계하면 시간이 많이 절약된다.

추상 클래스의 선언

public abstract class 클래스명 {
  // fields
  // constructors
  // methods
}

추상 클래스의 생성자

인스턴스화 될 수 없기 때문에 생성자가 필요 없다고 생각할 수 있으나, 자식 클래스에서는 반드시 부모 클래스의 생성자를 호출해야 하므로 추상 클래스 역시 생성자가 반드시 필요하다.

추상 메소드와 오버라이딩

모든 자식에게 같은 메소드가 적용되어도 상관없다면 오버라이딩을 할 필요가 없겠지만, 자식에 따라 다른 메소드가 필요하면 오버라이딩을 하면 된다.

더 나아가 모든 자식에게 시그니처는 같지만 실제 구현은 각각 다른 메소드가 필요할 수도 있다. 이럴 때 추상 메소드를 활용하면 된다.

책에서는 동물의 울음소리를 예로 들었다. 강아지, 고양이, 코끼리 모두 울기라는 공통적인 행위가 존재하지만, 그에 따른 소리는 각각 달라야한다. 세 객체에게 울기라는 행위는 공통적이지만 그 소리는 공통적인 부분이 없는데 억지로 추상 클래스에 빈 메소드를 작성하거나 하면 나중에 실수로 오버라이드를 깜빡하여 울음소리를 입력하지 않을 수도 있다. 이런 경우는 반드시 오버라이드를 하도록 추상 메소드로 선언해주자.

[public | protected] abstract 리턴타입 메소드명(매개변수, ...);

Last updated