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. 지나가는사람
    public Calculator(int left, int right){
    this.left = left;
    this.right = right;
    }

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

      이 개념이 맞는건가요?
    • 박현모
      감사합니다~ 잘 봤습니다~
    • 황금백수
      최고입니다
      핵심을 짚어주시네요 ㅎㅎ
    • 돌침대에서덤블링
      setOperands 함수 호출 없이 객체 생성시 left 와 right 값을 설정하기 위해서 생성자를 하나 더 만든겁니다.
      대화보기
      • 하면된다하자
        완료
      • ㅇㄹㅇㄹ
        맨 아래 예제에서 8~11행 코드의 용도는 뭔가요??

        public Calculator(int left, int right){
        this.left = left;
        this.right = right;
        }
        이것.

        밑에 셋 오프랜즈 메소드가 있는데 그 위에다가 또 저걸 써주는 이유는 뭐죠??
      • popinbompin
        complete
      • 데이터정복
        생성자의 복잡성과 super의 용도 이해 완료!
      • Younghun Liam Youn
        한번 강의 듣고는 이해가 잘 되지 않아서 '클래스 멤버와 인스턴스 멤버' 강의부터 다시 곱씹고 보니까 이해가 되네요! 혹시 저처럼 잘 이해가 안되시는 분들은 복습 한번 해보셔도 좋을 듯 합니다!
      • GoldPenguin
        감사합니다.
      • 완료.!
      • 김지현
        질문1 : 두 객체 모두 매개변수가 있는 객체를 생성하는 것인데 왜 상속을 받은 클래스에는 기본 생성자가 반드시 있어야 하는지 궁금합니다.
        - sub클래스 에서 super 키워드 사용시 super 클래스의 기본생성자가 필요없지만 , super키워드를 사용하지않을경우 super 클래스 에서 기본생성자가 있어야 합니다.

        질문2 : 만약 첫 번째 경우 기본 생성자가 자동으로 생성된다면 두 번째의 경우는 왜 기본 생성자가 자동으로 생성되지 않는지 궁금합니다.
        - 2번째의 경우
        매개변수가 있는 생성자 를 생성할 경우
        컴파일러가 컴파일시 생성자가 이미 있음으로 생성하지 않습니다.
        사용자가 기본 생성자를 직접 추가 해야 오류가 생기지 않습니다.

        기본 생성자가 자동으로 생성되는 경우는
        매개변수 가 있는 생성자가 없을경우 컴파일러 가 생성자가 없음을 확인하고 컴파일시 자동으로 생성합니다.
        대화보기
        • 상속이랑 연결되다 보니 참 와닿기 힘든 개념인듯...ㅠ
        • seokmin2004
          완료
        • C언어만마스터
          완료
        • yoon88
          완료/ 다시보기
        • darkoz89
          강의 수강중 질문있습니다!!

          초기화와 생성자 강의부분에서
          24번 째줄
          Calculator c1 = new Calculator(10, 20);
          객체를 생성 시킬 때는
          6번째 줄
          public Calculator(int left, int right) {
          this.left = left;
          this.right = right;
          }
          과 같이 기본 생성자 없이 매개 변수가 있는 생성자만 호출 시켜도 가능합니다. 그러나
          상속과 생성자 강의
          중간인 38번째 줄
          SubstractionableCalculator c1 = new SubstractionableCalculator(10, 20);
          객체를 생성하기 위해서는 기본생성자가 필요하여 기본생성자를 생성하거나 super를 써서 기본생성자를 만들었습니다.

          질문1 : 두 객체 모두 매개변수가 있는 객체를 생성하는 것인데 왜 상속을 받은 클래스에는 기본 생성자가 반드시 있어야 하는지 궁금합니다.
          질문2 : 만약 첫 번째 경우 기본 생성자가 자동으로 생성된다면 두 번째의 경우는 왜 기본 생성자가 자동으로 생성되지 않는지 궁금합니다.
        • gomu92
          저는 여기부터 막히네요 ㅠㅠ 힘!!
        • Keehwan Jee
          설명 잘하셨네요. 감사합니다
          대화보기
          • 미림_likelion
            수강 완료했습니다. 감사합니다.
          • nakra
            생성자를 정의한 클래스를 상속받기 위해서는
            부모 클래스에 기본 생성자를 넣어주거나
            자식 클래스에 슈퍼클래스를 이용한다는 개념이 맞나요?


            이 경우 부모 클래스에 기본 생성자가 있어야 이유는
            부모 클래스에서 초기화를 담당하던 생성자를 무력화시키고,
            자식 클래스에서 초기화를 담당하는 생성자만 작동하게 하기 위함인거죠?
          • J_Project
            감사합니다!
          • 꿈돌이
            부모클래스의 기본생성자가 애초에 없고 그 부모클래스코드가 수정이 어렵거나 안될때(다른개발자가만든코드)
            자식클래스에서 매개변수가 있는 생성자를 좀 만들어주고싶은데 부모클래스에 수정이 어려우니 자식이 super()를 통해서 부모클래스에 기본생성자가 있는것으로 나타낸다는말아닌가요??
          • 김인섭
            감사합니다.
          • 궁그미
            마지막 예제에 하위 클래스 생성자

            class SubstractionableCalculator extends Calculator {
            public SubstractionableCalculator(int left, int right) {
            super(left, right);
            }

            여기에서 super();가 들어간다면
            상위 클래스에서 기본 생성자인
            public Calculator(){}를
            따로 생성하지 않아도 된다는 말이죠?

            class Calculator {
            int left, right;

            // public Calculator(){}

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

            하위 클래스의 생성자에 super();가 없으면
            상위 클래스의 기본 생성자를 만들어줘야 하고요.
            제가 제대로 이해한 것이 맞나 궁금합니다.
          • YoungWoong Ha
            http://ideone.com/u15zAI

            부모클래스의 기본 생성자를 생성해준다는 건 알겠는데
            자녀클래스인 SubstractionableCalculator에서 입력한 값이 부모클래스에게까지 전달되서 sum, avg까지 결과값이 나온다는 건 이해가 안되네요.

            또 아래 부분은 삭제되어도 관계 없을것 같네요.
            public void setOprands(int left, int right) {
            this.left = left;
            this.right = right;
            }
          • 진격의숑숑
            감사합니다
          • 라떼
            어렵지만 복습을 통해 이해해야겠어요 ㅠ 감사합니다!
          • jimin_park(by.herO)
            아래 제 설명을 결론으로 도출시켜 보자면
            자식 클래스의 기본 생성자는 어떻게 될까요?

            public subclass(){

            super(){}

            }

            아마 이렇게 되있겠죠 ? 이걸 머리로써 이해하신다면 이번 수업은 전부 이해하신겁니다.
            대화보기
            • jimin_park(by.herO)
              어쩌면 자바에서 가장 어려운 개념이 바로 이 개념이 아닐까 사료됩니다.
              제가 아는 선에서 여러분들이 의아해 하시는 사항을 논리적으로 알려드릴까 합니다.
              자식클래스 SubstractionableCalculator로 객체(인스턴스)를 생성할 때
              자기자신 SubstractionableCalculator의 생성자를 이용하게되고 이 생성자안에
              부모클래스Calculator의 생성자가 암시적(implicit)으로 설정되어있어
              부모클래스의 인스턴스 변수를 초기화 해줍니다. 그것이 super(); 이고
              부모클래스에 default constructor(기본 생성자)가 없다면 그래서 에러가 발생 하는 것이죠.
              하지만 자식클래스 생성자안에 Super(parameter)를 따로 적어주면 부모클래스의 생성자를 호출할 때
              기본생성자가 아닌 Super(parameter)생성자로 부모클래스 인스턴스 변수를 초기화하게 되고
              그렇기 떄문에 부모클래스에 default생성자가 명시되어있지 않아도 에러가 발생하지 않는 것이죠.

              *설명이 장황한데 요점만 발췌한다면, 자식클래스로 객체를 생성할 떄 자식클래스 생성자를 통해
              객체가 생성이 되는데 이 생성자안에 부모클래스의 생성자가 묵시적 혹은 명시적으로
              선언되어 부모클래스의 인스턴스 변수들을 초기화하고
              그 나머지 자식클래스만이 가지는 인스턴스 변수들을 초기화 해준다 입니다.
              어찌보면 클래스라는 설계도 2개로 하나의 객체를 만들기 때문에 발생하는 복잡성이죠
            • 문의 드립니다.
              생성자와 초기화를 보면

              public Calculator(int left, int right) {
              this.left = left;
              this.right = right;
              }
              위 처럼 선언 후엔 왜 생성자가 없어도 되죠?

              상속과 생성저2를 보면
              public Calculator(int left, int right){
              this.left = left;
              this.right = right;
              }
              한 후 생성자가 없어서 오류가 발생하는데..

              두개는 동일한데.. 상속에서는 생성자가 있어야 하고,
              지금은 생성자가 없어도 된단 말씀인가요?

              약간 헤깔리네요.. 조언좀 부탁 드리겠습니다.
            • Bono Choi
              그렇게 사용될 수도 있다는 점을 들어주신거 같습니다. 맥락상 필요가 없다면 사용하지 않아도 되지만 저경우 example2에서 부모에서 정의내린 인자를 example3에서는 굳이 또 다시 정의 내릴 필요가 없으니 부모클래스의 생성자를 가져다 활용하는 거라 생각이 드네요.
              대화보기
              • 안녕하세요! 강의열심히 듣고 있는 학생입니다!
                궁금한부분이 있어 질문드려요
                package org.opentutorials.javatutorials.Inheritance.example2;
                package org.opentutorials.javatutorials.Inheritance.example3;
                두 예제 모두 setOprands 메소드는 사용하지않고있잖아요?

                근데 example2 의 코딩만으로도 잘 구현되는데
                example3에서 굳이 calculator 상위클래스에 생성자를 부여하는 이유는 뭐죠?
              • 감사합니다!!
              • joo0914krs
                감사합니다
              • 사토우하루
                super 은 클래스명 extends 뒤에 붙는 상속자 즉, 바로 위의 상속자를 말합니다.
                대화보기
                • JustStudy
                  고맙습니다
                • 강의잘듣고있습니다.
                  무쿵현따
                  대화보기
                  • 하얀달
                    꼭 그런것은 아닙니다. 저번강의 상속 강의와 같이 보면 이해가 조금 편하실텐데,

                    기본생성자가 필요한 이유는 상위클래스(상속을주는)의 생성자가 public Calculator(int left,int right) 와 같이
                    생성 되었을때에,

                    하위클래스(상속을받는)의 생성자에서 하위클래스 본인의 생성자 ..
                    즉, SubstractionableCalculator(int left, int right) 를 생성 했을때에 상위클래스에 기본생성자가 없으면 오류가
                    납니다. 직접실행해보시면 오류가 난다는 것을 아실거에요.

                    오류가 나는 이유는 상위클래스를 상속받았는데, 상위클래스에는 이미 생성자가 있다.

                    그런데, 그 생성자는 역할이 있죠, left , right 값을 받는 .. 그런데, 그 역할을 하지 못하니 오류가 나버립니다.
                    (어디까지나 예를 든 것 이니 ㅎㅎ 가볍게 들어주세요) ==> 이때 해결방법은 super(left,right)를 하면 됩니다.

                    그래서 상위클래스에 기본 생성자 Calculater() { } 를 주면 하위클래스에서 상위클래스에 있는 2개의 생성자중

                    기본생성자를 가져오게 되고, 아무런 문제가 없는것이죠. ( 기본생성자는 아무런 값을 받지 않으니까요 ^^)

                    이해가 되셨으면 좋겠네요 ~ 저도 한때 헷갈렸었던 부분이라 잘설명을 드리고 싶었으나..

                    저도 배우는 입장이다보니 조금은 설명이 부족함을 느낍니다.
                    대화보기
                    • 김트라슈
                      감사합니다
                    • 궁금합니다.
                      오늘 수업을 봤을때 생긴 의문인데

                      상속을 주는 상위 클래스의 경우에는 무조건 기본생성자를 가지고 있어야 되는 건가요?

                      public Calculator(int left, int right)와 같은 생성자외에 말이죠
                    • 감사합니다 ♡
                    • 송이
                      궁금한게 있어요
                      super는 부모 클래스를 의미한다는데 예를 들어 클래스를 상속에 상속에 상속 받을 경우에, 바로 위에 상속받았던 클래스가 super가 되는건가요? 아니면 상속의 최상위 클래스가 super가 되는건가요
                    • 오빠는다르다
                      감사합니다!!!
                    • 알려자바
                      호출시 매개변수 및 인자가 같은게 실행 되겠죠!!
                      대화보기
                      • meeya
                        클래스 이름을 좀 짧고 유니크하게 만들어주셨으면 좋겠습니다.
                        클래스 이름이 걔가 걔같고, 걔가 걔같아서....그거 구분하느라 개념이 안들어와요.
                        감사합니다.^^
                      • ctw1048@hanmail.net
                        음 한가지 궁금한게 생성자는 객체의 초기값을 잡아주기 위해서 만드느건데 생성자를 2개 만들 수 있다니 좀 놀랍네요.. 그럼 어떤 생성자가 적용되는걸까요?
                      버전 관리
                      egoing
                      현재 버전
                      선택 버전
                      graphittie 자세히 보기