본문 바로가기
JAVA 공부/JAVA 기초

[자바 기초]상속과 구성

by KyeongOUK 2020. 4. 28.

상속(Inheritance)

A(자식) is a B(부모)

부모클래스 A = new 자식클래스();


 

 우리가 생각하는 상속이라는 단어가 맞다. 현실 세계에서 부모님이 자식들에게 재산을 물려주는 것과 비슷하다. 차이라고 하면 자식(클래스)이 상속받고 싶은 부모(클래스)를 선택해서 물려받는다. 이때 상속받는 클래스를 자식 클래스, 하위 클래스 또는 서브 클래스라고 부른다. 상속을 해주는 클래스를 부모 클래스, 상위 클래스 또는 슈퍼 클래스라고 한다.

상속의 대상

 자식 클래스가 부모 클래스로부터 상속을 받게 되면 부모 클래스의 필 메서드 물려받게 된다. 단, 접근제어자가 private을 갖는 필드나 메소드는 상속이 불가하고, 패키지가 다를 경우 접근제어자가 default인 경우도 상속이 불가하다.(접근제어자에 대한 내용은 별도 포스팅 예정)

 

 

상속의 장점

 

 상속의 장점은 처음에 설명했던 것과 큰 차이가 없다. 중복된 코드를 줄일 수 있고, 유지 보수가 편리하며, 통일성이 있고 다형성을 구현할 수 있다.

상속의 방법(선언) - extends

 상속을 받는 방법은 간단하다. 상속받을 자식 클래스 뒤에 extends 키워드를 사용하고 부모 클래스를 적어주면 된다.

 그리고 자바에서는 자식 클래스가 여러 부모로부터 다중 상속을 받는 것은 불가능하다. 즉, 1개의 부모 클래스로부터의 단일 상속만 허용된다.  하지만 부모 클래스는 여러 개의 자식 클래스에게 상속이 가능하다.

[출처] [JAVA/자바] 상속의 개념 및 부모/자식 클래스|작성자 JOKER

 

 

여기서, 상속(Inheritance)이란 말 그대로 '부모의 유산을 물려받다'를 의미하고 이는 '자식이 부모의 것을 가진다'라고 할 수 있습니다. 객체 지향 프로그래밍에서도 이와 비슷한 개념으로 쓰이는데, 여기에서는 부모 클래스에 정의된 멤버를 자식 클래스가 물려받는 것을 말합니다. 즉, 상속을 통해 기존에 있던 클래스(부모 클래스)를 이용하여 새로운 클래스를 만들 수 있습니다. 이는, 기존의 것을 이용하여 만들어내기 때문에 적은 양의 코드로 새로운 클래스를 만들어 낼 수 있습니다.

 

상속을 해주는 부모 클래스는 상위 클래스(슈퍼 클래스, Super Class) 또는 기반 클래스(베이스 클래스, Base Class)라 하며, 상속을 받는 자식 클래스를 하위 클래스(서브 클래스, Sub Class), 또는 파생 클래스(유도 클래스, derived class)라고 합니다. 만약, 자바에서 상속을 받게 해주려면, 새로운 클래스 이름 뒤에 extends와 상속받고자 하는 클래스를 입력해주시면 됩니다.

 

class A { // A라는 클래스 생성
int num;
}

class B extends A { // B 클래스가 생성되고 그와 동시에 A 클래스를 상속받는다.
int num1;
}

class C extends B { // C 가 생성되고 그와 동시에 B 를 상속받고 B 클래스에 상속된 A 도 상속
int num2;
}

예제를 살펴보면, 클래스가 생성되고 num이라는 멤버변수를 A 클래스에 추가했습니다. 그 후에 B 클래스를 생성하고 A 클래스를 상속받죠. 즉, B 클래스에서 A 클래스의 모든 멤버를 가집니다. A 클래스의 num 멤버변수가 추가된 것이나 마찬가지죠. 그리고 마지막으로 C 클래스를 생성하면서 B 클래스를 상속받습니다. 그런데 여기서, B 클래스가 A 클래스에 상속됬기 때문에 C 클래스는 B 클래스와 A 클래스를 모두 상속받습니다.

 

여기서 상속의 특징을 잠깐만 살펴보겠습니다.

 

 다중 상속이 불가능합니다. 즉, 2개 이상의 클래스를 한꺼번에 상속할 수 없습니다.

● 부모의 생성자는 상속이 되지 않습니다.

● 부모 클래스가 가진 멤버변수와 메소드를 모두 상속받습니다.

● 부모 클래스 내에서 멤버 변수 또는 메소드가 private 접근 제한자를 사용하면 멤버 변수는 상속 받으나 바로 접근이 불가능하며, 메소드는 상속 되지 않는다.

● static 메서드 또는 변수도 상속이 된다.

● 동일한 이름의 변수가 부모 클래스와 자식 클래스에 둘 다 존재할 경우 부모 클래스의 변수는 가려진다.

 


출처: https://blog.hexabrain.net/116 [끝나지 않는 프로그래밍 일기]

 

상속의 위험성

 

서로 다른 패키지에 있으며 확장을 목적으로 설계되지 않았을때만 사용이 가능합니다.

extends을 위한 설계와 문서를 갖추거나 ,그럴 수 없다면 상속을 금지하라

 

어떻게 해야 상속이 안전해질까?

 

 

메서드를 재정의하는 것보다 새로 만드는 게 조금 더 나을 수도 있다. 훨씬 더 안전한 방법이긴 하지만 위험 요소가 전혀 없는 것은 아닙니다. 만일 하위 클래스에 추가한 메서드와 시그니처가 같고 리턴 타입만 다르다면 그 클래스는 컴파일조차 되지 않을 겁니다. 물론 리턴 타입도 같다면 재정의가 되겠지요?

 

 

상속은 언제해야할까?

 

클래스가 B가 클래스 A와 is-a 관계일때만 사용해야 합니다. 반드시 하위 클래스가 상위 클래스의 진짜 하위 타입인 상황에서만 쓰여야 합니다. 예를 들어 클래스 A를 상속하는 클래스 B를 만드려고 한다면, “B가 정말 A인가?” 를 생각해봐야 합니다. 예를 들자면? 와인 클래스를 상속하는 레드 와인 클래스. 그리고 레드 와인은 와인입니다.

그 조건이 아니라면 A를 클래스 B의 private 인스턴스로 두면 됩니다. 그러니까, A는 B의 필수 구성요소가 아니라 구현하는 방법 중 하나일 뿐입니다.

 

출처 : https://madplay.github.io/post/favor-composition-over-inheritance

 

A(자식) is a B(부모)

  부모클래스 객체명 = new 자식클래스(); is-a (상속) 개념

상속은 "is-a" 관계입니다. 구성은 "has-a"입니다.

C을 확장하는 대신 다른 클래스 C의 인스턴스를 클래스의 필드로 사용하여 작성합니다. 컴포지션이 상속보다 훨씬 나은 좋은 예는 현재 Java.util.Stack로 확장되는 Java.util.Vector입니다. 이것은 이제 실수로 간주됩니다. 스택 "is-NOT-a" 벡터; 요소를 임의로 삽입하거나 제거해서는 안됩니다. 대신 구성이되어야합니다.

 

불행히도 상속 계층 구조를 변경하면 기존 코드와의 호환성이 손상되므로이 디자인 실수를 수정하기에는 너무 늦습니다. Had Stack 상속 대신 컴포지션을 사용 했으므로 API 를 위반하지 않고 다른 데이터 구조를 사용하도록 항상 수정할 수 있습니다.

Josh Bloch의 저서 를 강력히 추천합니다. Java 2nd Edition

  • 항목 16 : 상속보다 구성을 선호하라
  • 항목 17 : 상속을위한 디자인 및 문서화

좋은 객체 지향 디자인은 기존 클래스를 자유롭게 확장하는 것이 아닙니다. 첫 번째 본능은 대신 작성하는 것입니다.

 


구성(composition)

A has a B(A는 B를 가지고 있다)

class A {

B b = new B();

b.B메서드();

}


기존 클래스를 확장하는 대신에 새로운 클래스를 만들고 private 필드로 기존 클래스의 인스턴스를 참조하게 하면 됩니다. 기존 클래스가 새로운 클래스의 구성요소로 쓰인다는 뜻에서 이를 컴포지션(Composition)이라고 합니다.

 

구성 <has a> 관계

 

- 다른 객체를 받아들여서 그 객체의 기능을 사용하는 것이다. (사람이 핸드폰을 사서 그 핸드폰의 기능을 사용하는 것)
 - 받아들인 객체의 자원(메소드/변수)을 사용할 수 있다.

 - 어떤 클래스 A가 또 다른 클래스인 B가 가진 기능을 사용하고 싶을때 B 클래스를 포함하면 B 클래스의 기능을 사용할 수 있다. 

 

A has a B (A는 B를 가지고 있다.)  

출처 : https://gbs1995.tistory.com/41

댓글