[whiteship] 6주차 - 상속

prayme·2020년 12월 27일
0
post-thumbnail

상속(Extending)

자식 클래스는 부모 클래스를 상속받을 수 있다.
상속을 받으면 무슨 일이 발생할까?

  • 부모 클래스의 field, method를 자식 클래스에서 정의하지 않고 사용할 수 있다.
  • 클래스들의 코드들이 간결해진다.
  • 클래스들간의 간계가 생기고 클래스들을 계층별로 관리하기가 용이해진다.

상속은 객체지향 프로그래밍에서 아주 중요한 개념이다.

포유류인간 클래스가 있다고 생각해보자
포유류 > 사람 으로 인간은 포유류에 속할 수 있다.
이를 클래스로 나타내면 아래와 같은 코드를 작성함으로써 상속을 구현할 수 있다.

public Human extend Mammalia  {
  ...
  ...
}

또한 큰 범주의 클래스에 작은 범주의 클래스를 저장할 때는 캐스팅이 필요없다.

  • 포유류 인간 = new 사람() 캐스팅 필요없음
  • 사람 인간 = new 포유류() 안됨
  • 사람 인간 = (사람) new 포유류() 캐스팅하면 됨
        Mammalia person1 = new Human();
        person1.getHeight();
        // person1.getNationality(); 자식 클래스의 메소드, 속성에는 캐스팅 없이 접근 불가
        // 그렇다면 왜 이렇게 쓸까? 다형성 때문에?

        Human person2 = new Human();
        person2.getNationality(); // 자식, 부모 모두 접근 가능

final class

final 명령어와 함께 클래스를 정의하면 부모 클래스가 될 수 없다. 만약 다른 클래스에 extends A를 추가하면 컴파일 에러가 발생한다.

대표적으로 java.lang.Stringfinal class의 예시이다.

final A {
  ...
}

java in a nutshell에서는 우리가 정의하는 대부분의 클래스들이 final이여야한다고 말한다.
클래스를 정의할 때 자식 클래스가 생기고 자식 클래스가 로직을 수정하는 것을 원치 않는다면 final 클래스를 붙이라고 한다.

자바 상속의 특징

  • 자바의 클래스는 하나의 클래스만 상속 받을 수 있다.
  • 자바의 모든 클래스의 최상위 클래스는 Object 클래스이다.
  • 자바의 클래스 계층은 Object를 루트로 가지는 트리 구조이다.
  • 부모 클래스는 superclass / 자식 클래스는 subclass라고 부른다.

super

super는 부모클래스를 나타낸다. this와 비슷한 동작을 한다.
마찬가지로 supersuper()가 있다.

super()는 자식 클래스의 생성자에서 선언할 수 있으며 선언 시 부모 클래스의 생성자를 호출한다.

super() 의 특징

  • super()는 부모 클래스의 생성자를 호출한다.
  • super()는 자식 클래스의 생성자에서만 사용가능하다.
  • super()는 반드시 자식 클래스 생성자의 첫줄에서 사용해야한다. 자식 클래스의 fieldmethod들을 조작하는 로직들보다 먼저 선언해야된다는 말이다.

모든 클래스를 생성할 때 제일 먼저 object의 생성자가 실행된다.
Object는 하나의 생성자만 가지고 있다.
생성자가 연쇄적으로 호출된다는 뜻이다. 객체가 생성될 때면 항상 생성자 체인이 호출된다 클래스 계층의 루트인 Obejct 까지 거슬러 올라가서.
왜냐하면 수퍼클래스의 생성자는 항상 서브클래스 생성자 로직에 첫줄에 선언하기 때문이다.

constructor chaining

생성자 체이닝을 설명하기 전에 앞서 설명한 것들을 다시 나열해보자

  • Object는 루트 클래스이다.
  • super()는 자식 생성자의 어떤 로직보다도 먼저 선언되어야 한다.

위와 같은 이유로 모든 클래스는 인스턴스화될 때 부모 클래스의 생성자가 super()에 의해 호출된다.
super()는 계속해서 부모 클래스에 접근해 결국에는 Object 클래스의 생성자부터 실행한다.

이런 동작을 constructor chaining이라고 한다.

추상 클래스

abstract를 붙임으로써 추상 클래스를 생성할 수 있다.

  • 모든 클래스는 abstract method가 있으면 반드시 abstract로 선언되어야 한다.
  • abstract class는 인스턴스화 할 수 없다.
  • abstract class를 상속받은 클래스는 abstract method들을 오버라이딩해야한다. 그리고 다른 부모-자식 관계처럼 abstract가 아닌 methodfield를 제공받는다.
  • abstract class를 상속받은 클래스를 concrete subclass라고 부르기도 한다.
  • 만약 모든 abstract methodimplement하지 않으면 그 subclass 자체도 추상 클래스가 되어버린다.
  • private, static, final method들은 abstract와 함께 쓸 수 없다. 왜냐하면 private, static, final은 오버라이딩할 수 없기 때문이다. 같은 이유로 final class는 어떠한 abstract method도 포함할 수 없다.
  • abstract method를 하나도 선언하지 않고서 classabstract로 선언할 수 있다. 이를 통해 반드시 하나 이상의 자식 클래스를 가지겠다고 명시할 수 있다. 물론 인스턴스화는 불가능하다.

Classloader 클래스가 abstract method를 포함하지 않는 abstract class의 좋은 예시이다.

method overriding

5주차 클래스 포스팅에서 오버라이딩을 정리했다.

Object class

  • Object는 자바 클래스 구조의 루트 노드이다.
  • Object는 유일하게 수퍼 클래스가 없다.
  • 모든 클래스는 Object를 직/간접적으로 수퍼 클래스로 가지지만 extend가 필요없다.
  • Object의 생성자는 하나 뿐이며 다른 클래스를 인스턴스화 할 때 항상 Object의 생성자가 먼저 호출된다.

Method Dispatch

어떤 메소드를 호출할지 결정하여 호출하는 과정을 말한다.
Static Method Dispatch, Dynamic Method Dispatch, Double Dispatch 가 있다.

Static Dispatch

위에서 언급한 코드를 먼저 보자

        Human person2 = new Human();
        person2.getNationality(); // 자식, 부모 모두 접근 가능

위의 코드처럼 호출해야 하는 함수가 명확할 때 즉, 컴파일 시점에 확정될 때를 말한다.

Dynamic Dispatch

abstract class Mammalia {
  abstract String getName();
}

public class Human {
  @Override
  public String getName() {
    return "사람입니다.";
  }
}

public class Whale {
  @Override
  public String getName() {
    return "고래입니다.";
  }
}

public static void main(String[] args) {
  Mammalia person = new Human();  <<  둘 다 컴파일단에서는 Mammalia의 getName인지
  person.getName();
  
  Mammalia whale = new Whale();   <<  Whale의 getName인지 알 수 없다.
  whale.getName();
}

위와 같이 abstract 혹은 interface의 메소드를 오버라이딩한 함수를 호출할 때 메소드가 동적으로 결정되는 것이다.

런타임 전에는 객체가 생성되지 않기 때문에 컴파일러는 Mammalia의 자식인 HumanWhale이 생성되는지 알 수 없다.

프로그램을 실행 시에는 동적으로 확인이 가능하다.
자바는 메소드를 호출할 때 호출한 객체를 매개 변수에 묵시적으로 함께 전달한다고 한다. 그렇기 때문에 메소드 내부에서 this를 통해 호출 객체에 대한 참조가 가능하다고 한다.

profile
잘하고 싶은 사람

0개의 댓글