본문 바로가기
  • 기업가 장준영
Java_1

Java_1_9 ( 상속 )

by 장준영 2020. 1. 10.

Java_1_8에서는 패키지접근 제어자에 대해서 알아봤다

오늘은 상속에 대해서 정리해 본다

앞 장에서 두세 번 정도 상속이라는 말이 나왔다.

현실세계에서는 부모님으로부터 무엇인가를 받으면 상속세를 내야 하지만 자바에서는 상속을 받아도 상속세를 내지 않아도 된다

그렇다면 도대체 자바에서의 상속이라는 것은 무엇일까?

다음 클래스 선언문을 유심히 보자

public class Child extends Parent

Child 뒤에 있는 것은 도대체 뭘까? extends라는 것은 자바의 예약어이며, 그 다음에 클래스 이름을 지정하면 그 클래스를 상속받는다는 말이다 그리고 상속을 해주는 클래스를 부모 클래스 상속을 받는 클래스를 자식 클래스라 부른다

보다 풀어 이야기하자면 "extend Parent"라고 하면 "Parent 클래스를 확장"한다는 말이다

이렇게 확장을 하면 부모 클래스에 선언되어 있는 public 및 protected로 선언되어 있는 모든 변수와 메소드를 내가 갖고 있는 것처럼 사용할 수 있다.

즉, 접근 제어자가 없거나 private로 선언된 것들은 자식 클래스에서 사용할 수 없다

여기서 상속에서 유의할 점들을 알아보자

  • 부모 클래스로부터 상속을 받은 자식 클래스가 생성자를 호출하면, 자동으로 부모 클래스의 기본 생성자가 호출된다
  • 부모 클래스에서는 기본 생성자들을 만들어 놓는 것 외에는 상속을 위해서 아므런 작업을 할 필요는 없다
  • 자식 클래스는 클래스 선언시 extends 다음에 부모 클래스 이름을 적어준다
  • 자식 클래스의 생성자가 호출되면, 자동으로 부모 클래스의 매개 변수 없는 생성자가 실행된다
  • 자식 클래스에서는 부모 클래스에 있는 public, protected로 선언된 모든 인스턴스 및 클래스 변수와 메소드를 사용할 수 있다

그런데, 왜 이런 상속이라는 개념을 만들었을까? 보통 우리가 살고이는 세상에서 상속이라고 이야기하면 물질적인 것만 이야기한다

하지만, 부모의 몸에 있는 유전적인 요소등도 부모로부터 상속 받는다

그리고, 부모와 자식이 같이 살면서 부모의 행동과 말을 따라서 배우게 된다

자바에서도 마찬가지로, 부모 클래스가 갖고 있는 변수와 메소드를 상속받음으로써, 여러분들이 개발할 떄 이중, 삼중의 일을 안해도 된다

아기가 배가 고프면 울고, 졸리면 자는 것과 같이 굳이 배우지 않아도 알아서 하는 것들이 있다.

여기서 "배우지 않아도" 되는 것들이 바로 자바에서는 부모 클래스에 있는 변수와 메소드라고 생각하면 된다

또 한 가지 예를 들어보자

대부분 이 블로그를 보는 독자들은 적어도 한대의 pc나 노트북이 있을 것이다

개발자들이 좋아하는 맥북 프로를 예를 들어 생각해보자

맥북 프로는 신모델이 나오면 달랑 한가지만 있는 것이 아니다. 13인치 15인치 모델이 있고

13인치와 15인치도 두 개정도의 모델로 나뉜다. 즉, 한 가지 기준이 되는 모델이 있고, 그 모델에서 약간씩 다르게 한다

각 모델을 처음부터 따로 디자인한다고 하면 엄청난 시간과 인건비가 소요될 것이다. 하지만

하나를 제대로 만들어 놓고, 그것에서 파생되는 것들을 조금씩 바꾸어 판매하면 사용자는 기호에 따라 여러 모델을 살 수 있을 것이다

자바에서의 상속도 바로 이와 비슷한 개념이다, 하나의 클래스를 잘 만들어 놓은 게 있으면, 그 클래스를 상속받아 내가 추가적인 기능을 넣을 수 있다

상속이라는 것은 매우 많은 장점을 갖고 있다

그런데, 여러분들이 꼭 하나 추가로 기억해야 하는 것이 있다. 자바에서는 다중 상속이 안 된다

다시 말해서, extends 뒤에 클래스를 하나만 써야지, 두 개 이상 클래스를 나열하면 컴파일이 되지 않는다

extends 뒤에는 클래스를 하나만 써서 단일 상속밖에 안 된다는 것을 꼭 기억해 주기 바란다

상속과 생성자의 관계

앞 절에서 상속에 대해서 정리할 때 다음과 같이 말했다

  • 부모 클래스에서는 기본 생성자를 만들어 놓는 것 이외에는 상속을 위해서 아무런 작읍을 할 필요는 없다

만약 부모 클래스에서 기본 생성자가 없다면 어떻게 될까?

기본 생성자를 만들지 않고 실행 해보자

정상적으로 처리된다. "뭐 별 문제 없네"라고 생각할 수도 있다.

하지만, 부모 클래스에 매개 변수를 받는 메소드가 있을 경우에는 이야기가 달라진다

컴파일하면 에러를 내뿜는다

자식 클래스의 생성자가 실행할 때 부모 클래스의 매개 변수가 없는 기본 생성자가 없다는 에러가 발생한다

이러한 문제가 발생하는 이유는 부모 클래스의 상속을 받은 자식 클래스의 모든 생상자가 실행될 때

부모클래스의 기본생성자를 찾는데 부모 클래스에 정의한 생성자는 String을 매개 변수로 받는 생성자 밖에 없기 떄문이다

앞서 이야기했지만, 매개 변수가 있는 생성자를 만들었을 경우에는 기본 생성자는 자동으로 만들어지지 않는다

이러한 경우엔 해결할 수 있는 방법은 두 가지다

  1. 부모 클래스에 "매개 변수가 없는" 기본 생성자를 만든다
  2. 자식 클래스에서 부모 클래스의 생성자를 명시적으로 지정하는 super()를 사용한다

자바에는 super라는 예약어가 있다

메소드처럼 super()로 사용하면 부모 클래스의 생성자를 호출한다는 것을 의미한다

메소드처럼 사용하지 않고 super.printName()로 사용하면 부모 클래스에 있는 printName()이라는 메소드를 호출한다는 의미다

방금 실행한게 실행오류가 발생하는 이유도 자식 클래스의 생성자에는 여러분들이 지정하지 않아도, 자식 클래스를 컴

파일할 때 자동으로 super()라는 문장이 들어가기 때문이다

super()를 사용하여 생성자를 호출할 떄에는 모호하게 null을 넘기는 것보다는 호출하고자 하는 생성자의 기본타입을 넘겨주는 것이 좋다

부모 클래스에 매개 변수가 있는 생성자만 있을 경우에는 super()을 이용해서 부모 생성자를 꼭 호출해야만 한다

자식 클래스의 생성자에서 super()를 명시적으로 지정하지 않으면, 컴파일시 자동으로 super()가 추가된다

그리고, 부모 클래스의 생성자를 호출하는 super()는 반드시 자식 클래스의 생성자에서 가장 첫줄에 선언되어야만 한다

메소드 Overriding

자식 클래스에서 부모 클래스에 있는 메소드와 동일하게 선언하는 것을"메소드 Overriding"이라고 한다

접근 제어자, 리턴 타입, 메소드 이름, 매개 변수 타입 및 개수가 모두 동일해야만 "메소드 Overriding" 이라고 부른다

부모 클래스에 선언되어 있는 메소드와 동일하게 선언되어 있는 메소드를 자식 클래스에 선언하면 자식 클래스의 메소드만 실행 된다

생성자의 경우 자동으로 부모 클래스에 있는 생성자를 호출하는 super()가 추가 되지만, 메소드는 그렇지 않다

이게 바로 메소드 "Overriding" 이다

Overriding에도 주의점이 있다

  • 부모 클래스를 Overriding 한 자식 클래스의 메소드의 리턴 타입을 다르게 리턴하면 안 된다

  • 부모 클래스를 Overriding 한 자식 클래스의 접근 제어자 범위를 확대하는 것은 문제가 안 되지만, 축소되는 것은 문제가 된다 즉, public > protected > package-private > private(오른쪽으로 갈수록 접근 권한이 좁아짐)의 순인데, 부모 클래스에서 public으로 선언한 것을 자식이 private로 선언하면 안 된다는 말이다. 부모가 만약 private로 선언했으면 자식은 어떤 것으로 선언하든지 상관 없다

이제 살펴본 Overriding에 대해 정리해 보자면

  • 메소드 Overriding은 부모 클래스의 메소드와 동일한 시그니처를 갖는 자식 클래스의 메소드가 존재할 때 성립된다
  • Overriding된 메소드는 부모 클래스와 동일한 리턴 타입을 가져야만 한다
  • Overriding된 메소드의 접근 제어자는 부모 클래스에 있는 메소드와 달라도 되지만, 접근 권한이 확장되는 경우에만 허용된다. 접근 권한이 축소될 경우에는 컴파일 에러가 발생한다

이 정도로 요약할 수 있다

많은 분들이 앞장에서 배운 Overloading과 이 장에서 배운 Overriding을 혼동한다. 다음과 같이 외워 보자

  • Overloading : 확장(메소드의 매개 변수들을 확장하기 떄문에, 확장)
  • Overriding : 덮어 씀(부모 클래스의 메소드 시그니처를 복제해서 자식 클래스에서 새로운 것을 만들어 내어 부모 클래스의 기능은 무시하고, 자식 클래스에서 덮어 씀)

자식 클래스에서 할 수 있는 일들을 다시 정리해보자

Java_1_9에서 배운 내용들은 자바로 개발을 할 떄에는 매우 중요하다. 그러므로 상속에 대한 내용을 정리하는 차원에서 자식 클래스에서 어떤 것들을 할 수 있는지 정리해 보자

생성자

  • 자식 클래스의 생성자가 호출되면 자동으로 부모 클래스의 매개 변수가 없는 기본 생성자가 호출된다. 명시적으로 super()라고 지정할 수도 있다
  • 부모 클래스의 생성자를 명시적으로 호출하려면 super()를 사용하면 된다

변수

  • 부모 클래스에 private로 선언된 변수를 제외한 모든 변수가 자신의 클래스에 선언된 것처럼 사용할 수 있다
  • 부모 클래스에 선언된 변수와 동일한 이름을 가지는 변수를 선언할 수도 있다. 하지만, 이렇게 엎어 쓰는 것은 권장하지 않는다
  • 부모 클래스에 선언되어 있지 않는 이름의 변수를 선언할 수 있다

메소드

  • 변수처럼 부모 클래스에 선언된 메소드들이 자신의 클래스에 선언된 것처럼 사용할 수 있다
  • 부모 클래스에 선언된 메소드와 동일한 시그니처를 사용함으로써 메소드를 Overriding할 수 있다
  • 부모 클래스에 선언되어 있지 않은 이름의 새로운 메소드를 선언할 수 있다

오늘은 상속에 대해 알아 보았다

이정도만 알았어도 오늘 하루는 유익한 하루이다

'Java_1' 카테고리의 다른 글

Java_1_11 ( 인터페이스와 추상클래스, final, enum )  (0) 2020.01.11
Java_1_10 ( Object클래스 )  (0) 2020.01.10
Java_1_8 ( 패키지와 접근 제어자 )  (0) 2020.01.09
Java_1_7 ( 참조 자료형 )  (0) 2020.01.08
Java_1_6 ( 배열 )  (0) 2019.12.09

댓글