프로그래밍 공방

[Java의 정석] Chapter 7. 상속 / Inheritance 본문

Java

[Java의 정석] Chapter 7. 상속 / Inheritance

hyosupsong 2021. 1. 10. 23:12

상속 / Inheritance

기존의 클래스를 재사용하여 새로운 클래스를 작성하는것

- 적은 양의 코드로 새로운 클래스를 생성할 수 있다.
- 코드를 공통적으로 관리할 수 있다.

-> 코드의 재사용성을 높이고 코드의 중복을 제거하여 프로그램의 생산성과 유지보수에 크게 기여한다.

1
2
3
class 자식클래스 extends 부모클래스 {
    // ...
}
cs

부모 클래스 : 상속 해주는 클래스 ( 조상 클래스, 상위 클래스, 기반 클래스 )
자식 클래스 : 상속 받는 클래스 ( 자손 클래스, 하위 클래스, 파생된 클래스 )

< Parent - Child 클래스의 관계도 >

상속의 특징

- 생성자, 초기화 블럭은 상속되지 않고 멤버만 상속된다.
- 자손 클래스의 멤버 개수는 조상 클래스보다 항상 같거나 많다.
* 부모 멤버 중 private이나 default가 사용된 멤버들은 상속은 받지만 자손 클래스로부터의 접근은 제한된다.

전체 프로그램을 구성하는 클래스들을 면밀히 설계 분석하여 클래스간의 상속관계를 적절히 맺어주는 것이 객체지향 프로그램에서 가장 중요한 부분이다.

자손 클래스의 인스턴스를 생성하면 부모 클래스의 멤버와 자식 클래스의 멤버가 합쳐진 하나의 인스턴스가 생성된다.

포함 관계 / Composite

1
2
3
4
class Circle {
    Point p = new Point();    // 포함 관계
    int r;
}
cs

하나의 거대한 클래스를 생성하는 것보다 단위별로 여러 개의 클래스를 작성한 다음 이 단위 클래스들을 포함관계로 재사용하면 보다 간결하고 손쉽게 클래스를 작성할 수 있다.

클래스 간의 관계 결정 ( is - a / has - a )

is - a : ~ 이다. ( 상속 )
has - a : ~ 가지고 있다. ( 포함 )

[ 참고 ]

C++은 여러 클래스로부터 상속을 받는 다중 상속을 허용하지만 Java는 단일 상속만을 허용한다.

다중 상속의 단점

- 클래스 간의 관계가 복잡해진다.
- 상속받는 멤버간의 이름이 같은 경우 구별할 수 있는 방법이 없다.

이에 비해 단일 상속은 클래스간의 관계가 보다 명확해지고 코드를 더욱 신뢰할 수 있게 만들어준다.

Object 클래스

모든 클래스의 상속 계층도의 제일 위에 위치하는 조상 클래스
(아무 클래스도 상속받지 않는 모든 클래스는 Object 클래스를 상속받는다.)

오버라이딩 / Overriding

부모 클래스로부터 상속받은 메서드의 내용을 변경하는것

오버라이딩의 조건

- 이름이 같아야 한다.
- 매개변수가 같아야 한다.
- 리턴 타입이 같아야 한다.

접근 제어자와 예외는 제한된 조건 내에서 다르게 할 수 있다.
1. 접근 제어자는 부모 클래스의 메서드보다 좁게 변경할 수 없다.
2. 부모 클래스의 메서드보다 많은 수의 예외를 선언할 수 없다.(단순히 개수가 아닌 범위)
3. 인스턴스 메서드를 클래스 메서드로 혹은 반대로의 변경은 불가능하다.

오버로딩(Overloading) - 오버라이딩(Overriding) 차이

오버로딩 : 기존에 없는 새로운 메서드를 추가하는 것
오버라이딩 : 부모로부터 상속받은 메서드의 내용을 변경하는 것

super / super( )

super

자식 클래스에서 부모 클래스로부터 상속받은 멤버를 참조하는데 사용되는 참조변수
* 부모 클래스의 멤버와 자식 클래스의 멤버가 중복 정의되어 서로 구별해야 하는 경우에만 super를 사용하는 것이 좋다.
동일한 이름이 중복으로 부모와 자식에 있는 경우에만 super / this의 값이 다르고 부모에만 있는 경우에는 값이 같다.

super( )

this( )와 마찬가지로 super( ) 역시 생성자이다. 부모 클래스의 생성자를 호출하는데 사용된다.
* 자식 클래스의 인스턴스 생성 -> 자식, 부모의 멤버가 모두 합쳐진 인스턴스가 생성 -> 이때 부모 클래스 멤버의 생성과 초기화가 필요하므로 자식 클래스의 생성자에서 부모 클래스의 생성자 호출이 필요 -> 생성자의 첫줄에서 부모 클래스의 생성자를 호출 (자식 클래스의 멤버가 부모 클래스의 멤버를 사용할 수 있기 때문)

Object 클래스를 제외한 모든 클래스의 생성자 첫 줄에는 생성자(같은 클래스의 다른 생성자 또는 부모의 생성자)를 호출해야 한다. 그렇지 않으면 컴파일러가 자동적으로 super( ); 를 생성자의 첫 줄에 추가한다.

주의
생성자가 정의되어 있는 클래스에는 디폴트 생성자가 없으므로 super( ); 부분에서 컴파일 에러가 발생할 수 있다.
(따라서 사용하지 않더라도 빈 생성자를 만들어주는 것이 좋다.)

부모 클래스의 멤버변수는 부모의 생성자에 의해 초기화 되도록 하는 것이 좋다.
(부모 클래스에 변경이 생기는 경우 자식 클래스에서 하나씩 수정해주는 것보다 관리에 용이하다.)