Java

상속과 생성자

편리함을 위해서 어떠한 기능을 수용하면 그 기능이 기존의 체계와 관계하면서 다양한 문제를 발생시킨다. 그 문제를 한마디로 줄여서 말하면 복잡도의 증가라고 할 수 있다. 이번 시간에는 생성자가 상속을 만나면서 발생한 복잡성을 보여줄 생각이다. 그 맥락에서 super이라는 키워드의 의미도 중요하게 다뤄질 내용이다. 

이번 수업을 이해하기 위해서는 기본 생성자의 성질에 대한 이해가 선행되야 한다. 아래의 예제를 보자.

package org.opentutorials.javatutorials.Inheritance.example4;
public class ConstructorDemo {
	public static void main(String[] args) {
		ConstructorDemo  c = new ConstructorDemo();
	}
}

위의 예제는 에러를 발생시키지 않는다. ConstructorDemo 객체를 생성할 때 자동으로 생성자를 만들어주기 때문이다. 하지만 아래의 예제는 에러가 발생한다.

package org.opentutorials.javatutorials.Inheritance.example4;
public class ConstructorDemo {
    public ConstructorDemo(int param1) {}
	public static void main(String[] args) {
		ConstructorDemo  c = new ConstructorDemo();
	}
}

매개변수가 있는 생성자가 있을 때는 자동으로 기본 생성자를 만들어주지 않는다. 따라서 위의 예제는 존재하지 않는 생성자를 호출하고 있다. 이 문제를 해결하기 위해서는 아래와 같이 기본 생성자를 추가해줘야 한다.

package org.opentutorials.javatutorials.Inheritance.example4;
public class ConstructorDemo {
    public ConstructorDemo(){}
	public ConstructorDemo(int param1) {}
	public static void main(String[] args) {
		ConstructorDemo  c = new ConstructorDemo();
	}
}

이제 본론으로 들어가보자. 상속 토픽의 첫 번째 예제를 조금 수정해서 생성자를 통해서 left, right의 값을 설정한다.

package org.opentutorials.javatutorials.Inheritance.example2;

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 SubstractionableCalculator(int left, int right) {
		this.left = left;
		this.right = right;
	}

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

public class CalculatorConstructorDemo4 {
	public static void main(String[] args) {
		SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
		c1.sum();
		c1.avg();
		c1.substract();
	}
}

이해를 돕기 위해서 아래와 같이 차이점만을 부각한 이미지를 첨부하였다. 붉은색으로 표시된 부분이 달라진 부분이다.

실행결과는 아래와 같다.
30
15
-10

SubstractionableCalculator의 생성자로 left와 right의 값을 받아서 초기화시키고 있다. 만약 클래스 Calculator가 메소드 setOprands가 아니라 생성자를 통해서 left, right 값을 설정하도록 하고 싶다면 아래와 같이 코드를 변경해야 할 것이다.

package org.opentutorials.javatutorials.Inheritance.example3;

class Calculator {
    int left, right;
	
	public Calculator(int left, int right){
		this.left = left;
		this.right = 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 SubstractionableCalculator(int left, int right) {
		this.left = left;
		this.right = right;
	}

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

public class CalculatorConstructorDemo5 {
	public static void main(String[] args) {
		SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
		c1.sum();
		c1.avg();
		c1.substract();
	}
}

달라진 부분은 아래와 같다.

위의 코드를 실행하면 오류가 발생한다. 오류의 내용은 아래와 같다.

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    Implicit super constructor Calculator() is undefined. Must explicitly invoke another constructor

	at org.opentutorials.javatutorials.Inheritance.example3.SubstractionableCalculator.<init>(CalculatorConstructorDemo5.java:26)
	at org.opentutorials.javatutorials.Inheritance.example3.CalculatorConstructorDemo5.main(CalculatorConstructorDemo5.java:38)

즉 상위 클래스인 Calculator의 생성자가 존재하지 않는다는 의미다. 하위 클래스가 호출될 때 자동으로 상위 클래스의 기본 생성자를 호출하게 된다. 그런데 상위 클래스에 매개변수가 있는 생성자가 있다면 자바는 자동으로 상위 클래스의 기본 생성자를 만들어주지 않는다. 따라서 존재하지 않는 생성자를 호출하게 되기 때문에 에러가 발생했다. 이 문제를 해결하기 위해서는 아래와 같이 상위 클래스에 기본 생성자를 추가하면 된다.

package org.opentutorials.javatutorials.Inheritance.example3;

class Calculator {
    int left, right;
	
	public Calculator(){
		
	}
	
	public Calculator(int left, int right){
		this.left = left;
		this.right = 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 SubstractionableCalculator(int left, int right) {
		this.left = left;
		this.right = right;
	}

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

public class CalculatorConstructorDemo5 {
	public static void main(String[] args) {
		SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
		c1.sum();
		c1.avg();
		c1.substract();
	}
}

차이점은 아래와 같다.

그런데 상위 클래스인 Calculator에는 left와 right 값을 초기화할 수 있는 좋은 생성자가 이미 존재한다. 이것을 사용한다면 하위 클래스에서 left와 right의 값을 직접 설정하는 불필요한 절차를 생략할 수 있을 것이다. 어떻게 하면 상위 클래스의 생성자를 호출할 수 있을까?

super

super는 상위 클래스를 가리키는 키워드다. 예제를 통해서 super의 사용법을 알아보자.

package org.opentutorials.javatutorials.Inheritance.example3;

class Calculator {
    int left, right;
	
	public Calculator(){}
	
	public Calculator(int left, int right){
		this.left = left;
		this.right = 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 SubstractionableCalculator(int left, int right) {
		super(left, right);
	}

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

public class CalculatorConstructorDemo5 {
	public static void main(String[] args) {
		SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
		c1.sum();
		c1.avg();
		c1.substract();
	}
}

차이점은 아래와 같다.

super 키워드는 부모 클래스를 의미한다. 여기에 ()붙이면 부모 클래스의 생성자를 의미하게 된다. 이렇게 하면 부모 클래스의 기본 생성자가 없어져도 오류가 발생하지 않는다.

하위 클래스의 생성자에서 super를 사용할 때 주의할 점은 super가 가장 먼저 나타나야 한다는 점이다. 즉 부모가 초기화되기 전에 자식이 초기화되는 일을 방지하기 위한 정책이라고 생각하자.

댓글

댓글 본문
작성자
비밀번호
  1. 홍주호
    20190912 완료
  2. 다나가
    190902 - 수강완료!!!!
  3. 하여진
    쓔펄!!
  4. doevery
    수강완료
  5. 지미츄
    감사합니다
  6. 자스
    글을 꼼꼼히 읽어보세용 님 답글 감사합니다.
    예제 코드에 기본생성자가 포함되어 있어 질문드리게 됐는데,
    맨 아래 글을 다시 읽어보니 정확히 적혀있네요~ㅎ
    대화보기
    • 자스
      좆문가님 답변 감사합니다.
      예제 코드에 public Calculator(){} 포함되어 있어 혼돈이 와서 질문드리게 됐습니다.
      대화보기
      • 글을 꼼꼼히 읽어보세용
        super 키워드는 부모 클래스를 의미한다. 여기에 ()붙이면 부모 클래스의 생성자를 의미하게 된다. 이렇게 하면 부모 클래스의 기본 생성자가 없어져도 오류가 발생하지 않는다.
        대화보기
        • 좆문가
          이해를 못하셨나본데, Calculator()를 따로 덧붙이지 않고 쓰기 위해서 super(~~)를 쓰는 겁니다
          대화보기
          • 자스
            맨 마지막 예제에서 super 를 선언할 때 public Calculator(){} 기본 생성자도 정의 해야 하나요?
            없어도 코드는 정상 실행이 되네요
          • 얼그레이
            어려운 고비를 하나 넘긴...? 넘길락 말락 하는 느낌이네요... 감사합니다 :) 190710
          • 날아라미어캣
            패키지 안에 동일클래스명때문일겁니다.
            대화보기
            • 마마마마
              코드를 돌리면 class 옆에 calculator가 빨간색이 뜨나요.. 아시는분 있나요
            • 6/17시작
              6.25 완료
            • 이현정
              6.24 9시 25분 완료
            • 한성호
              첫번째 동영상 안에 제목이 '생상자'라고 되어 있네용
            • JLetter
              감사합니다.
            • silver94
              강의 잘듣고갑니다^!
            • 자바공부
              setOprands 메소드는 없어도 실행되는데 왜 쓰신 건가요??
            • 개발세발이 알려드리지요
              2가지 질문을 하신걸로 보이는데요,
              1. 생성자를 따로 정의하지 않는다면 기본생성자가 자동 생성되며, 생성자를 따로 정의해준다면, 자바는 생성자를 따로 생성해주지않는다. (질문자님은 매개변수가 있는 생성자를 정의했을때만 자바가 생성자를 생성해주지 않는걸로 적어두신 것 같기에 좀더 명확히 적었습니다.)
              2. 상속을 받은 자식클래스는 생성하자마자 자바가 부모클래스의 생성자를 호출하도록 되어있습니다. 이때, 부모클래스의 생성자에 매개변수가 존재한다면, 그것을 해결할 방법으로 2가지가 존재하는데요. 첫째로는 부모클래스에 기본 생성자를 생성해주는 것이고, 둘째로는 자식클래스의 생성자안에 부모클래스의 매개변수 생성자인 super(매개변수);를 선언해주는 것입니다.
              ★참고로 super(매개변수);는 자식클래스의 생성자안에서 가장 처음에 존재해야합니다. 그 이유는 위에도 언급했지만, 자식클래스가 부모클래스를 상속받는 순간 부모클래스의 생성자를 호출하도록 되어있기 떄문이지요 ★
              대화보기
              • 영웅문
                php에선 __construct 쓰면 되는걸
                자바에선 하나하나 생성자 써줘야되니 불편한감이있네요 ㅋㅋㅋ

                왜 php가 자유롭고 편한지 자바를 배우면서 느낌 ㅋㅋ
              • 라또마니
                두번 들으니 개념이 잡히네요~~
              • j-graphy
                2019. 2. 18. 학습 완료
              • 호두
                고맙습니다.
              • java 123
                일단 제가 이해한 바로는 기본생성자는 자바에서 자동으로 만들어주는 생성자 이지만

                클래스에 매개변수가있는 생성자를 정의하면 기본생성자는 만들어지지 않는다 라는 것이고

                자식클래스가 생성자를 호출할때는 부모클래스의 기본생성자만을 필요로 하기 때문에

                부모클래스의 매개변수가있는 생성자가 있음에도 불구하고 부모클래스의 기본생성자를 따로만든건가요??

                너무 헷갈리네요
              • ㅁㅇㄴㄹ
                자식클래스의 left와 right 가 10 20인것은 이해가 되는데 왜 부모클래스의 left right 값도 10 20으로 바뀌는지 이해가 안됩니다 extends 사용하면 원래 같이 바뀌는건가요?
              • 웅이
                마지막 소스코드(super 내용) 코드를 똑같이 따라하니까
                calculator와 SubstractionableCalculator 가 'The type SubstractionableCalculator is already defined'
                이런 오류가 뜨는데...
                댓글에 아무도 그런말씀이 없으시네요 ㅠㅠ
                저만 그런건가요?
              • 기수니
                아, 다시 되세김질 해서 super() 재대로 확인 해보네요
              • 김성연
                감사합니다
              • 0.8009787737609289
                햇갈린다
              • 백용빈
                SubstractionableCalculator가 Calculator를 상속하고 있기 때문입니다.
                대화보기
                • 김시진
                  안녕하세요 정말 도움이 많이 되고있습니다 ㅜㅜ 제가 남들보다 이해력이 조금 부족해서 못따라가는 경향이 있지만 이 동영상 보고 정말 많은 도움이 되고있습니다 ㅜㅜ

                  혹시 jsp강의는 안하시나요??ㅠㅠ
                • 전하연
                  감사합니다
                  2018.8.19 15:05
                • 뚱이
                  뚱인데요
                • phoenix
                  안녕하세요
                • 서호
                  전역변수와 지역변수에 대해서 다시한번 봐보세요.
                  대화보기
                  • 유자
                    메인함수에서 하위클래스 생성자 호출->
                    하위클래스에서 상위클래스의 생성자를 호출
                    (진홍님의 말대로 상위클래스의 초기화가 먼저 이루어져야합니다!
                    상위클래스가 존재해야 하위클래스도 존재할 수 있기 때문이죠)->
                    상위 클래스 생성자 작동(또는 변수 초기화)->
                    하위클래스 생성자 작동->
                    메인 함수로 다시 돌아옴

                    뿌리를 찾으러 거슬러 올라갔다가 다시 내려오는 형식이라고 생각하시면 됩니다!
                    그래서 super를 호출할 때 하위클래스 생성자 정의 부분에 가장 먼저 써주는 이유기도 하구요.
                    제 방식대로 이해해서 혹시 틀린 부분이 있을 수 있지만...도움이 되었으면 좋겠습니다!
                    대화보기
                    • 이태호
                      7/4
                      super(left,right); 의 사용법
                    • 멀캠A_Son
                      완료
                    • 진홍
                      변수는 상위클래스에서 초기화가 되있습니다. 말그대로 하위클래스란것은 상위클래스 코드에다 추가한것이라고 생각하시면 된다고 생각합니다.
                      대화보기
                      • 유나
                        class SubstractionableCalculator extends Calculator {
                        public SubstractionableCalculator(int left, int right) {
                        this.left = left;
                        this.right = right;
                        }
                        }
                        이 부분은 Class에 left, right라는 변수를 선언해주지 않았는데 왜 this를 쓰나요??
                        변수를 선언하지않았는데 this.left = left 라는 말을 쓸 수 있는건가요?
                      • B.tory
                        생성자와 setOperand의 기능이 같아보여도 쓰임이 다르다고 생각합니다.
                        밑에서 객체를 생성하고 싶을때
                        Caculator c1 = new Caculator();
                        Caculator c2 = new Caculator(5,3);
                        이렇게 생성된다하면 c1에서는 setOparand메서드가 있어야 두 변수를 추가 할 수 있습니다.
                        즉, 객체를 생성하는 동시에 변수를 넣는 것이 아닌 후에 추가하고 싶은 경우 setOprand메서드가 있어야 가능하다는 것입니다.
                        대화보기
                        • ㅎㅇ
                          생활코딩님의 설명이랑 저의 이해력이랑 너무안맞는거같아요ㅠㅠ
                          생활코딩님 설명듣고 이해가안되서
                          제가 스스로 계속 프로그래밍하면서
                          꺠달았네요 ㅠㅠ
                        • ㅎㅇ
                          생활코딩님의 설명이랑 저의 이해력이랑 너무안맞는거같아요ㅠㅠ
                          생활코딩님 설명듣고 이해가안되서
                          제가 스스로 계속 프로그래밍하면서
                          꺠달았네요 ㅠㅠ
                        • 지나가는사람
                          public Calculator(int left, int right){
                          this.left = left;
                          this.right = right;
                          }

                          이건 클래스의 생성자 입니다.
                          생성자를 배우기 전에 setOperand라는 메소드를 만들어서 left, right값을 쓴건데요.
                          생성자를 배웠기 때문에 저 setOperand를 없애도 무방하죠.
                          생성자를 없애는 것보다 setOperand를 없애는 것이 더 좋습니다.
                          대화보기
                          • 아빠가간다.
                            두세번 보고 이해했습니다. 아니 깨달았다고 해야하나...
                            super 메소드를 설명하기 위해 좀 억지로 돌아온 느낌이 있네요...
                            조금 이해하기 어려웠습니다.
                          • 열정하나
                            음 좀더 다시 보고 공부해야겠다.
                          • 5월 2일 상속과 생성자.
                            하위클래스에 생성자가 있어 근데 상위클래스에 기본 생성자가 없어 그러면 에러가 난다. 하위클래스의 생성자가 실행되기 위해서는 상위클래스의 기본생성자가 실행되어야 한다. 만약 상위클래스의 기본생성자를 만들지 않고 사용하려면 하위클래스 생성자에 super키워드를 이용하여 상위클래스의 생성자를 초기화한 후에 하위클래스의 생성자 초기화를 진행하도록 해야한다.

                            이 개념이 맞는건가요?
                          • 박현모
                            감사합니다~ 잘 봤습니다~
                          • 황금백수
                            최고입니다
                            핵심을 짚어주시네요 ㅎㅎ
                          버전 관리
                          egoing
                          현재 버전
                          선택 버전
                          graphittie 자세히 보기