2008. 7. 22. 23:20

chapter 7. 상속과 다형성

상속이란 하위클래스가 상위클래스의 멤버(인스턴스 변수, 메소드)를 물려 받는 것
하위클래스는 별도의 메소드와 인스턴스 변수를 추가할 수 있고 상위클래스의 메소드를 오버라이드 할 수 있다.
그러나 인스턴스 변수는 오버라이드 하지 않는다. 인스턴스 변수가 특별한 행동을 정의하지 않기 때문에...

상속 트리의 설계
1. 공통적인 속성과 행동이 들어있는 객체를 찾는다.
2. 공통적인 상태와 행동을 나타내는 클래스를 설계한다.
3. 특정 하위클래스 유형에만 적용되는 행동(메소드 구현)이 필요한지 결정한다.
4. 공통적인 행동이 필요한 하위클래스를 두 개 이상 찾아서 추상화의 개념을 더 폭넓게 활용할 수 있는지 찾는다.
5. 클래스 계층 구조를 완성한다.

하위클래스에서 상위클래스에 있는 버전의 메소드와 새로 오버라이드한 버전의 메소드 둘 다 사용하고 싶을 경우에는 먼저 상속 받은 메소드를 실행시킨 후, 하위클래스에서만 실행할 메소드를 처리한다.

상속을 활용하여 설계할 때의 주의점
어떤 클래스가 다른 클래스(상위클래스)를 더 구체화한 형식이라면 상속을 활용한다.
같은 일반적인 형식에 속하는 여러 클래스에서 공유해야 하는 어떤 행동(구현된 코드)이 있다면 상속을 활용한다.
그러나 객체지향 프로그래밍에 있어서 상속의 핵심 기능 가운데 하나지만 행동을 재사용하는 데 있어 무조건 최선의 방법이 아니라는 점을 주의해야 한다.
상위클래스와 하위클래스 사이의 관계가 위에 있는  두 가지 규칙에 위배된다면 어떤 코드를 다른 클래스에서
재사용할 수 있다는 이유만으로 상속을 사용하면 안된다.
하위클래스와 상위클래스 사이에서 'A는 B이다' 관계가 성립하지 않는다면 상속을 사용하지 않는다.

상속의 주요 특징
자바에서는 하위클래스가 상위클래스를 확장한다고 한다.
하위클래스는 상위클래스에 있는 모든 public으로 지정한 인스턴스 변수와 메소드를 상속하지만 private로 지정한 인스턴스 변수와 메소드는 상속하지 않는다.
메소드는 오버라이드 가능하지만 인스턴스 변수는 오버라이드 하지 않는다.
'A는 B이다' 라는 관계를 확인한다.(한방향으로만 작동한다.)
하위클래스에서 메소드를 오버라이드하고 하위클래스의 인스턴스 변수에 대해 그 메소드를 호출하면 오버라이드된 버전의 메소드가 호출된다.(맨 밑에 있는것이 호출 됨)
B라는 클래스가 A라는 클래스를 확장하고 C는 B를 확장한다면 클래스 B는 클래스 A이고 클래스 C는 클래스 B이고 클래스 C는 클래스 A이다.

상속의 장점
코드가 중복되는 것을 방지할 수 있다.
(그러나 특정 메소드의 인자나 리턴 형식, 메소드명과 같이 상위클래스에 있는 것 가운데 하위클래스에서 반드시 필요로 하는 것을 변경하면 심각한 문제가 생길 수 있다.)
일련의 클래스를 위한 공통적인 규약(protocol)를 정의할 수 있다.

다형성의 이해
객체 선언과 대입의 세 가지 단계
Dog myDog = new Dog();
    1.          2.      3.
1. 레퍼런스 변수를 선언한다.
2. 객체를 만든다.
3. 객체와 레퍼런스를 연결한다.
주요사항은 레퍼런스 유형과 객체 유형이 똑같아야 한다는 점이다.

하지만 다형성을 활용하면 레퍼런스와 객체가 다른 유형이어도 됩니다.
Animal myDog = new Dog();

다형성을 사용하면 레퍼런스 유형을 실제 객체 유형의 상위클래스 유형으로 지정할 수 있다.

Animal[] animals = new Animal[5];
animals [0] = new Dog();
animals [1] = new Cat();
animals [2] = new Wolf();
animals [3] = new Hippo();
animals [4] = new Lion();

for (int i = 0 ; i < animals.length ; i++ ) {
  animals[i].eat();
  animals[i].roam();

의문사항
인자와 리턴 유형에 대해서도 다형성을 적용할 수 있다.


대부분의 상속계층은 넓지만 깊지는 않다.
클래스의 소스코드를 직접 접근할 수 없지만 어떤 클래스의 메소드가 작동하는 방식을 바꾸고 싶을 때는 클래스를 확장한 후 메소드를 오버라이드해서 더 나은 코드를 만들면 된다.
상속이 안되는 경우.
클래스를 private로 지정할 경우
클래스를 final로 지정할 경우
내부 클래스(inner class)인 경우
오버라이드할 수 없도록 만들고 싶은 경우에는 final 클래스를 사용한다.

상위클래스의 메소드를 오버라이드할 때이 규칙
1. 인자는 동일해야 하고, 리턴 유형은 호환 가능해야 한다.
2. 메소드를 더 접근하기 어렵게 만들면 안된다(public 메소드를 오버라이드해서 private 메소드를 만드는 등등)

메소드 오버로딩이란 이름이 같고 인자 목록이 다른 메소드 두 개를 만드는 것.
오버로딩을 활용하면 호출하는 쪽의 편의를 위해 같은 메소드를 서로 다른 인자 목록을 가진 여러 버전으로 만들 수 있다. 오버로드하는 메소드에서는 상위클래스에서 정의한 다형성 계약을 이행하지 않아도 되기 때문에 메소드 오버로딩은 훨씬 더 융통성이 좋다고 할 수 있다.
규칙 & 장점
1. 리턴 유형이 달라도 된다.
2. 리턴 유형만 바꿀 수는 없다.(인자 목록을 반드시 변경해야 한다.)
3. 접근 단계를 마음대로 바꿀 수 있다.