Java

상속

상속이란?

객체지향을 통해서 달성하고자 하는 목표 중에서 가장 중요한 것은 재활용성일 것이다. 상속은 객체지향의 재활용성을 극대화시킨 프로그래밍 기법이라고 할 수 있다. 동시에 객체지향을 복잡하게 하는 주요 원인이라고도 할 수 있다.

상속(Inheritance)이란 물려준다는 의미다. 어떤 객체가 있을 때 그 객체의 필드(변수)와 메소드를 다른 객체가 물려 받을 수 있는 기능을 상속이라고 한다. 부모와 자식의 관계에 따른 비유를 들을 수도 있지만, 비유는 얻는 것보다 잃는 것이 많기 때문에 구체적인 코드를 통해서 상속을 알아보자. 

객체지향 수업의 첫 번째 예제인 CalculatorDemo 예제로 이동하자. 이 예제에서 등장하는 객체 Calculator는 더하기와 평균에 해당하는 sum과 avg 메소드를 가지고 있다. 그런데 이 객체가 가지고 있는 기능에 빼기를 추가하고 싶다. 가장 쉬운 방법은 이 객체에 빼기를 의미하는 substract를 추가해서 아래와 같이 사용하고 싶다.

Calculator c1 = new Calculator();
c1.setOprands(10, 20);
c1.sum();
c1.avg(); 
c1.substract();

아래와 같은 경우에 속한다면 객체에 메소드를 추가하는 것이 어렵다.

  1. 객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다. 변경 할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substarct이 사라진다. 이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.
  2. 객체가 다양한 곳에서 활용되고 있는데 메소드를 추가하면 다른 곳에서는 불필요한 기능이 포함될 수 있다. 이것은 자연스럽게 객체를 사용하는 입장에서 몰라도 되는 것까지 알아야 하는 문제가 된다.

이제부터 언어의 개발자가 되어 보자. 기존의 객체를 그대로 유지하면서 어떤 기능을 추가하는 방법이 없을까? 이런 맥락에서 등장하는 것이 상속이다. 즉 기존의 객체를 수정하지 않으면서 새로운 객체가 기존의 객체를 기반으로 만들어지게 되는 것이다. 이때 기존의 객체는 기능을 물려준다는 의미에서 부모 객체가 되고 새로운 객체는 기존 객체의 기능을 물려받는다는 의미에서 자식 객체가 된다. 그 관계를 반영해서 실제 코드로 클래스를 정의해보자.

부모 클래스와 자식 클래스의 관계를 상위(super) 클래스와 하위(sub) 클래스라고 표현하기도 한다. 또한 기초 클래스(base class), 유도 클래스(derived class)라고도 부른다. 
package org.opentutorials.javatutorials.Inheritance.example1;

class Calculator {
    int left, right;

	public void setOprands(int left, int right) {
		this.left = left;
		this.right = right;
	}

	public void sum() {
		System.out.println(this.left + this.right);
	}

	public void avg() {
		System.out.println((this.left + this.right) / 2);
	}
}

class SubstractionableCalculator extends Calculator {
	public void substract() {
		System.out.println(this.left - this.right);
	}
}

public class CalculatorDemo1 {

	public static void main(String[] args) {

		SubstractionableCalculator c1 = new SubstractionableCalculator();
		c1.setOprands(10, 20);
		c1.sum();
		c1.avg();
		c1.substract();
	}

}

실행결과는 아래와 같다.

30
15
-10

위의 코드를 하나씩 분해해서 생각해보자.

class SubstractionableCalculator extends Calculator {
    public void substract() {
		System.out.println(this.left - this.right);
	}
}

우선 새로운 클래스인 SubstractionableCalculator을 정의했다. 이 클래스의 본체에는 sbstract라는 메소드만이 존재한다. 하지만 이 클래스를 인스턴스화한 c1은 아래와 같이 정의하지 않은 메소드들을 호출하고 있다. 물론 잘 동작한다.

SubstractionableCalculator c1 = new SubstractionableCalculator();
c1.setOprands(10, 20);
c1.sum();
c1.avg();
c1.substract();

이것이 가능한 이유는 extends Calculator 때문이다. 이것은 클래스 Calculator를 상속 받는다는 의미다. 따라서 SubstaractableCalculator는 Calculator에서 정의한 메소드 setOprands, sub, avg를 사용할 수 있게 된다. 이것이 프로그래밍의 역사에서 대단한 진전으로 평가받는 상속의 기본적인 의미다. 상속을 통해서 코드의 중복을 제거할 수 있었고, 또 부모 클래스을 개선하면 이를 상속받고 있는 모든 자식 클래스들에게 그 혜택이 자동으로 돌아간다. 다시 말해서 유지보수가 편리해진다는 것이다.  재활용성과 중복의 제거, 그리고 유지보수의 편의는 서로 다른 목적으로 가지고 있지만, 하나가 좋아지면 자연스럽게 다른 쪽도 좋아지는 관계에 있다는 것을 다시 한 번 환기해주는 대목이다.

생각을 조금 더 말랑말랑하게 하기 위해서 Calculator을 상속 받는 클래스를 하나 더 만들어보자. 이 클래스는 곱하기를 할 수 있는 클래스다.

package org.opentutorials.javatutorials.Inheritance.example1;

class MultiplicationableCalculator extends Calculator {
    public void multiplication() {
		System.out.println(this.left * this.right);
	}
}

public class CalculatorDemo2 {

	public static void main(String[] args) {

		MultiplicationableCalculator c1 = new MultiplicationableCalculator();
		c1.setOprands(10, 20);
		c1.sum();
		c1.avg();
		c1.multiplication();
	}

}

결과는 아래와 같다.

30
15
200

그럼 상속한 클래스를 다시 상속할 수 있을까? 물론 가능하다. 아래의 예제는 곱하기가 가능한 클래스인 MultiplicationableCalculator을 상속받고 있다.

package org.opentutorials.javatutorials.Inheritance.example1;

class DivisionableCalculator extends MultiplicationableCalculator {
    public void division() {
		System.out.println(this.left / this.right);
	}
}

public class CalculatorDemo3 {

	public static void main(String[] args) {

		DivisionableCalculator c1 = new DivisionableCalculator();
		c1.setOprands(10, 20);
		c1.sum();
		c1.avg();
		c1.multiplication();
		c1.division();
	}

}

이것이 상속의 기본적인 개념이다. 어렵지 않다. 하지만 장점이 있으면 단점도 있는 법이다. 프로그래밍의 세계에서는 이 상속의 효용을 수용하기 위해서 꽤나 많은 대가를 치러야 했다. 그 대가를 한마디로 표현하자면 복잡도의 증가라고 이야기할 수 있을 것이다. 객체지향을 두 개의 시즌으로 나눈다면 클래스와 인스턴스에 대한 이해가 시즌1이라면 상속은 객체지향 내에서의 시즌2라고 할만하다. 

댓글

댓글 본문
작성자
비밀번호
  1. BlueFox
    안드로이드 스튜디오 강좌도 올려주셨으면 좋겠네요.ㅎㅎ 자바 배우고 안드로이드도 배울라고 하는데, 생활코딩에 없어서 많이 아쉬워요..
  2. 찬찬찬
    너무나 감사합니다 복받으세요
  3. Joon Lee
    상속이 잘 이해됐습니당!
  4. 감사합니다!!
  5. egoing
    고맙습니다~
    대화보기
    • flyoverthehimalaya
      감사합니다.
      강의 잘 듣고 있습니다.
    • 지나가던
      클래스를 CalculatorDemo3 한개로 돌리면안나와요

      CalculatorDemo1 이랑 CalculatorDemo2랑 다있는상태에서

      Demo3를 돌리시면 나옵니다.
      대화보기
      • Weaver
        좋은 강의 감사합니다~
      • 이고잉님 강의 예제와 함께 설명해주셔서인지 이해도 엄청 잘되고 매번 이고잉님의 예제를 직접 프로그램에 돌려보면서 수업을 듣습니다!
        오늘 MultiplicationableCalculator을 상속받은 DivisionableCalculator를 사용한 예제는 오류도 발생하지 않는데 출력이 되지 않더라구요 왜 안되나요?
        c1.setOprands(10,20); 부터 c1.multiplication();까지는 결과가 출력이 되는데 마지막 c1.division();은 결과출력이 되지않아요ㅠ_ㅠ 궁금합니다!
      • joo0914krs
        감사합니다
      • 강의를 잘 듣고 있습니다. 감사합니다.

        그런데 Substract 가 아니고 subtract입니다.
      • JustStudy
        고맙습니다
      • 강의잘듣고있습니다.
        1.객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다. 변경 할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substarct이 사라진다. 이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.

        객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다.

        변경 할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substarct이 사라진다.
        원작자가 소스를 제공해줘서 소스가 있어서 substract를 추가한 상태에서 사용하다가 원작자가 프로그램을 업데이트 합니다. 뭔가 기능이 강화되어서 업데이트를 했을테니 저도 그 기능들이 쓸모가 있다면 업데이트를 해야겠죠? 그 과정에서 제가 임의로 추가한 substract라는 메소드는 사라집니다. 업데이트를 하게되면 원작자의 프로그램을 다시 받는다는 뜻인데 원작자의 프로그램에는 내가 필요한 substract라는 메소드가 없기 때문입니다.

        이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.
        업데이트를 할 때마다 substract를 다시 추가해줘야하고 그러러면 업데이트 할 때마다 메소드를 다시 추가해줘야 한다는 것을 항상 기억하고 있어야 한다는 말인데 이 얼마나 귀찮은 일인가.. 라고 하셨습니다
        대화보기
        • 김트라슈
          감사합니다
        • 유동
          *subtract 인 것 같아용 강의 잘 보고 있습니다 감사해요~!
        • 감사합니다♡
        • 오빠는다르다
          감사합니다!!!!
        • 소백
          다음 강의 "상속과 생성자" 편 보시면 해결되실듯 합니다.
          대화보기
          • 이바몬
            처음 calculator 클라스에서 생성자를 선언하고 상속자 클라스 substractionablecalculator를 선언할때 오류가 발생하는데 그 이유는 무엇인가요
          • 꼬맹이
            객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다. 변경 할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substarct이 사라진다. 이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.

            --> A 라는 객체가 있는데 이 안에는 a,b,c 라는 함수들이 있다고 칩니다
            하지만 사용자가 A 객체에 d 라는 함수를 추가하면 A 객체에는 a,b,c,d 함수가 있겠죠?
            이상태에서 A라는 객체를 만든 개발자가(?) A 객체를 원소스에서 e 라는 함수를 추가하려고 업데이트를 하는데
            과연 사용자가 쓰고있는 a,b,c,d 를 base 로 해서 업데이트 할까요? 아니면 원소스 a,b, c 를 base 로 해서 업데이트할까요? 결론은 원소스 a,b,c를 업데이트 해서 a,b,c,e 로 만든다는말입니다. 걀국 사용자가 추가한 d 함수는 날라가는거죠.


            객체가 다양한 곳에서 활용되고 있는데 메소드를 추가하면 다른 곳에서는 불필요한 기능이 포함될 수 있다. 이것은 자연스럽게 객체를 사용하는 입장에서 몰라도 되는 것까지 알아야 하는 문제가 된다.
            -> 아래 제다이님이 설명잘해주신거같음.
          • 야쿠
            이해가 안돼서 두번 봤더니 감이 좀 오네요ㅋ 감사합니다~~~
          • Golive
            나 태어나 이런것을 배워가니 기가막히게 좋구나~!! (반말 죄송합니다;;)
          • 기초에 충실하자
            상속은 객체지향의 핵심인 것 같습니다. 중복 코딩을 피하고 재활용을 극대화하며 효율적인 코드관리를 할 수 있는거죠.
          • 박첩구드
            바뀐 분위기가 좋네용 ㅎㅎㅎ 밧데리 신경까지 써주시고 그린아이티까지 ㄷㄷ
          • Byunghawk Lee
            잘 봤습니다.
            그런데 굳이 하위 클래스를 만들어야 하는 경우가 생기나?하는 생각이 드네요. 특별한 경우 한번 사용하고 잘 사용되지 않는 것을 만들어 사용할 때 사용할 수 있겠다 싶긴 하지만 그냥 클래스에 다 넣어 사용하는 것이 낫지 않나 싶은데....(제 생각엔, 요즘 메모리나 용량등을 생각해보면 큰 차이가 없을 것 같고 코딩에 시간 소비가 덜 할 것같네요)
          • love opentutorials
            사랑합니다. 선생님!
          • cocohodu
            좋은강의 감사합니다
          • positives4all
            정말 명쾌한 설명에 감탄합니다. 감사합니다!
          • BLSFTWR
            System.out.println(left + right);
            이부분의 left right 는 매개변수이고
            this.left this.right 는 Calculator 의 변수입니다

            입력을 받게 도와주는게 left right고
            실제 값을 this.left에 left값을 저장해주는 거라고 생각합니다
            대화보기
            • Hwuiwon Kim
              갑자기 궁금한건데

              class Calculator {
              int left, right;

              public void setOprands(int left, int right) {
              this.left = left;
              this.right = right;
              }

              public void sum() {
              System.out.println(this.left + this.right);
              }

              여기서 sum 부분의 System.out.println(this.left + this.right); 이부분을

              System.out.println(left + right); 로 변경해도 결과는 똑같은데 굳이 this.* 를 붙이는 이유가 있나요?
            • 제다이
              1. 이 부분은 제가 생각하는게 맞는지 확실하지 않아 대답을 해드리기 어렵네요.

              2. a,b,c 메소드가 있는 A객체를 여러군데에서 사용하고 있다고 합시다. 그런데 A객체를 가지고 이것저것 만들다보니 어느 한 부분에서 d 메소드가 필요해서 A객체에 d 메소드를 추가시켰습니다. 그러면 A객체는 a,b,c,d 메소드를 가지고 있겠죠. 그러면 d 메소드를 추가시키기 전, a,b,c 메소드만 있어도 되는 다른부분에선 필요없는 d 메소드가 생겼고 필요없는 기능이 생긴겁니다.
              그리고 제가 만든 이 A객체를 다른 사람이 필요해서 가져다 쓴다고 합시다. 이 A객체를 가져다 쓰는 사람은 a,b,c 메소드만 필요해서 A객체를 가져왔는데, 여기에는 a,b,c,d 메소드가 있는겁니다. 그러면 A객체를 사용하는 사람은 a,b,c,d 메소드 내용을 다 알아야 자신에게 d 메소드가 불필요한지 알 수 있겠죠. 사용자 입장에선 몰라도 되는 부분을 알아야 하는 문제가 생긴겁니다.
            • urimago
              저도 아랫분이 말씀하신 부분이 이해가 안가네요;
            • 하나
              다른부분은 다 이해가는데 아직도

              객체를 자신이 만들지 않았다. 그래서 소스를 변경할 수 없다. 변경 할 수 있다고 해도 원 소스를 업데이트 하면 메소드 substarct이 사라진다. 이러한 문제가 일어나지 않게 하기 위해서는 지속적으로 코드를 관리해야 한다.
              객체가 다양한 곳에서 활용되고 있는데 메소드를 추가하면 다른 곳에서는 불필요한 기능이 포함될 수 있다. 이것은 자연스럽게 객체를 사용하는 입장에서 몰라도 되는 것까지 알아야 하는 문제가 된다.

              이 두 부분만 이해가 안되네요;; 좀 더 쉽게 설명해주실 수 있는 분 계시나요? 제가 이해력이 딸려서요 ㅠㅠ
            • 풍운도장
              이고잉님, 상속 완전 이해했습니다.
              끝까지 해서 객체 지향 개념 꼭 잡고, 중학생 아들 방학 때 알려주고 싶습니다.
            • Donghyun Kim
              Substract는 Subtract의 자주 쓰이는 오용 표현이라고 합니다.
              프랑스어나 스페인어 중에 같은 의미를 갖고 있는 단어 안에 s가 들어감으로써
              영어의 오용도 많아졌다는 설이 있네요.

              전산학 단어로는 add-substract time 이라고 가감산 시간이라는 용어가 있는데
              이게 맞는지 틀린지는 저도 모르겠습니다.;;
            • 김곰
              오프라인 강의도 하시나요?
              강의 개념 안마다 다 댓글을 남기고 있습니다..ㅋ
            • 학원에서 뭔말인지 못알아먹어서 이거 강의 정주행 중인데
              이렇게 쉽게 설명해 주신다니 너무너무 감사합니다.
            • Akinaro
              강의 잘 보고있습니다 ㅎㅎ
              근데 '빼다'는 subtract 입니당 ㅋㅋ서브트랙트인데 서브스트랙트라고 쓰셨네용 ㅎㅎ
            • 아짱
              자바책 여러권보다 훨씬 좋습니다.

              이 강의는 정말 구조를 이해하기 쉽게 설명해준다..

              너무 감사합니다.
            • 아이폰 터치감 느낌이네요~~ 감성공학같아 >.< 짱
            • 담론
              분위기 전환과 함께 강의 듣는 분들의 시력과 배터리까지 고려하시다니... ^^
            • 환글
              좋은 강의 잘 들었습니다. 아~~ 이 강의는 인문과 기계의 만남 같아요^^
            • 성민
              상속 왠지 윈도우의 VHD랑 비슷한 개념이네요...
            • Haewon Lee
              이야 선구자들께서 대단한 걸 만드셨네.
              상속이거 하나로 얼마나 편리해졌을까.
            • egoing
              두개 이상의 클래스가 부모가 될 수 없다는 것입니다. 자바는 하나의 클래스만 부모가 될 수 있어요.
              대화보기
              • cloud9osh
                저는 c++을 배워본적이 없는데요. c++에서는 다중상속이 가능하지만 자바에서는 안된다고 들었습니다. 자바에서 다중상속이 안된다는 것은 어떤 의미인지 알 수 있을까요?
              • egoing
                그것은 뒤에서 배우게 됩니다.

                http://opentutorials.org......531
                http://opentutorials.org......061
                대화보기
                • seokhyung jang
                  질문이 있습니다..
                  같은 pacage 안에서는 다른 java 파일에 서로 다른 java파일에 클래스가 있어도 서로 같이 상속을 하는지가
                  궁금합니다....
                  만약된다면 또 궁금해지는건 다른 pacage 에 있는 class 파일들도 서로 상속이 가능한지도... 궁금합니다.ㅎ
                • 중3땅딸이
                  ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
                  대화보기
                  • 이고잉 안티팬
                    고잉이형 옆구리에서 딸기향 날 것 같아요.
                  버전 관리
                  egoing
                  현재 버전
                  선택 버전
                  graphittie 자세히 보기