[Object] 12. 다형성


앞에서 배운 상속의 목적은 코드 재사용이 아니다. 상속은 타입계층을 구조화하기 위해 사용해야한다.
상속을 통해 타입 계층을 구조화하여 다형성을 구현하는 방법에 대해 알아보자.

다형성

추상인터페이스에 대해 코드를 작성하고 이 추상 인터페이스에 대해 서로 다른 구현을 연결할 수 있는 능력.
쉽게 말해, 여러 타입을 대상으로 동작할 수 있는 코드를 작성할 수 있는 방법.

오버로딩 다형성

하나의 클래스 안에 동일한 이름의 메서드가 존재하는 경우.

public class Money{
    public Money plus(Money amount) {...}
    public Money plus(int amount) {...}
    public Money plus(long amount) {...}
}

강제 다형성

언어가 지원하는 자동적인 타입변환이나 사용자 정의 타입변환으로 동일한 연산자를 다양한 타입에 사용할 수 있는 방식.

System.out.println(1 + "3") /// 13

매개변수 다형성

인스턴스 변수나 메서드 매개변수 타입을 임의의 타입으로 선언한 후 사용 시점에 구체적인 타입으로 지정

ArrayList<T>

포함다향성(서브타입 다형성)

메세지가 동일하더라도 수신한 객체의 타입에 따라 실제로 수행되는 행동이 달라지는 능력. 서브타입 다형성. 가장 널리 알려진 형태의 다형성.

public class Movie{
    private DiscountPolicy discountPolicy;
    public Money calculateFee(Screening screening){
        return fee.minus(discountPolicy.calculateFee(screening));
    }
}

포함다형성을 구현하는 가장 일반적인 방법은 상속을 사용하는것이다.
포함다형성을 위한 전제조건은 자식클래스가 부모클래스의 서브타입이어야한다는것이다.
이렇듯 상속의 진정한 목적은 다형성을 위한 서브타입계층을 구축하는것이다.

상속의 양면성

아래 코드를 예시로 상속에 대해 알아보자.

public class Lecture{
    private int pass;
    private String title;
    private int scores;
    
    public int average();
    public String evaluate();
}
public class GradeLecture extends Lecture{
    pirvate String grade;

    @Override
    public String evaluate(){
        System.out.println("eval");
    }

    public int average(int score);
}

데이터 관점의 상속

자식 클래스의 인스턴스 안에 부모 클래스의 인스턴스를 포함하는것.

행동 관점의 상속

부모클래스가 정의한 일부 메서드를 자식 클래스의 메서드로 포함시키는것.
부모클래스의 모든 public method는 자식클래스의 public interface에 포함된다.
런타임에 시스템이 자식클래스에 정의되지 않은 메서드가 있을 경우 이 메서드를 부모클래스 안에서 탐색한다.

메서드 탐색 과정

164_1
위와 같이 메서드가 존재하지않으면 parent 포인터를 따라 부모클래스를 차례대로 훑어 나가면서 적절한 메서드가 존재하는지 검사한다.

업캐스팅

부모클래스(Lecture) 타입으로 선언된 변수에 자식클래스(GradeLecture)의 인스턴스를 할당하는것이 가능하다. 이를 업캐스팅이라한다.

Lecture lecture = new GradeLecture(..);

동적바인딩

선언된 변수 타입이 아니라 메세지를 수신하는 객체의 타입에 따라 실행되는 메서드가 결정된다. 이를 동적바인딩이라한다.

self참조

객체가 메세지를 수신하면 컴파일러는 self참조라는 임시변수를 자동으로 생성한 후 메세지를 수신한 객체를 가리키도록 설정한다. 동적 메서드 탐색은 slf가 가리키는 객체의 클래스에서 시작해 상속계층 역방향으로 이뤄지며 탐색종료된 후 self참조는 자동소멸된다.

자동적인 메세지 위임

상속계층은 객체가 자신이 이해할수없는 메세지를 부모클래스에게 전달하는 물리적인 경로를 정의하는것으로 볼 수 있다. 메세지는 상속 계층을 따라 자동적으로 부모에게 위임된다.

메서드 오버라이딩, 오버로딩

오버라이딩

evaluate() 처럼 자식이 부모클래스 메서드를 오버라이딩하면 자식클래스가 먼저 검색되고, 붐클래스 메서드를 감추게된다.

오버로딩

GradeLecture lecture = new GradeLecture(...);
lecture.average(3);

이경우 탐색은 GradeLecture에서 종료.

GradeLecture lecture = new GradeLecture(...);
lecture.average();

이경우 Lecture에서 탐색을 종료.

이렇게 시그니처는 다르고 이름은 동일한 메서드가 공존하는것을 메서드 오버로딩이라고한다.
클라이언트관점에서 부모, 자식 메서드 모두 호출이 가능하다.

super참조

자식클래스에서 부모를 재사용해야하는경우? super참조를 이용해 부모클래스를 호출할 수 있다.

상속 대 위임

self 참조

GradeLecture 인스턴스에 포함된 Lecture인스턴스의 self는 누구인가? GradeLecture이다. self참조는 항상 메세지를 수신한 객체를 가리킨다.

위임

자신이 수신한 메세지를 다른 객체에게 동일하게 전달해서 처리를 요청하는것을 위임이라고 한다.




© 2020. by berrrrr

Powered by berrrrr