생활코딩

Coding Everybody

코스 전체목록

닫기

overriding

창의적인 상속

상속은 상위 클래스의 기능을 하위 클래스에게 물려주는 기능이다. 그렇다면 하위 클래스는 상위 클래스의 메소드를 주어진 그대로 사용해야 할까? 만약 그래야 한다면 제약이 상당할 것이다. 이런 제약을 벗어나려면 하위 클래스가 부모 클래스의 기본적인 동작방법을 변경할 수 있어야 한다. 이런 맥락에서 도입된 기능이 메소드 오버라이딩(overriding)이다.

상속 시간의 예제를 살펴보자. 이 예제는 클래스 Calculator의 기본적인 동작 방법을 상속 받은 SubstractionableCalculator에 빼기 기능을 추가하고 있다. 이것은 상위 클래스의 기능에 새로운 기능을 추가한 것이다. 만약 상위 클래스에서 물려 받은 메소드 sum을 호출했을 때 아래와 같이 그 결과를 좀 더 친절하게 알려줘야 한다면 어떻게 해야할까?

실행 결과는 30입니다.

상속 토픽의 예제를 조금 변경해보자.

package org.opentutorials.javatutorials.overriding.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 sum() {
		System.out.println("실행 결과는 " +(this.left + this.right)+"입니다.");
	}
	
	public void substract() {
		System.out.println(this.left - this.right);
	}
}

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

아래는 차이점이다.

실행결과는 아래와 같다.

실행 결과는 30입니다.
15
-10

메소드 sum이  SubstractionableCalculator에 추가 되었다. 실행결과는 c1.sum이 상위 클래스의 메소드가 아니라 하위 클래스의 메소드 sum을 실행하고 있다는 것을 보여준다. 하위 클래스 입장에서 부모 클래스란 말하자면 기본적인 동작 방법을 정의한 것이라고 생각할 수 있다. 하위 클래스에서 상의 클래스와 동일한 메소드를 정의하면 부모 클래스로부터 물려 받은 기본 동작 방법을 변경하는 효과를 갖게 된다. 기본동작은 폭넓게 적용되고, 예외적인 동작은 더 높은 우선순위를 갖게하고 있다. 이것은 공학에서 일반적으로 발견되는 규칙이다. 이것을 메소드 오버라이딩(overriding)이라고 한다.

오버라이딩의 조건

상위 클래스에서 정의하고 있는 메소드 avg는 계산 결과를 화면에 출력하고 있다. 그런데 계산 결과를 좀 더 다양하게 사용하기 위해서 메소드 avg가 화면에 결과를 출력하는 대신 계산 결과를 리턴해주면 좋겠다. 그래서 아래와 같이 코드를 고쳐봤다.

package org.opentutorials.javatutorials.overriding.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 sum() {
		System.out.println("실행 결과는 " +(this.left + this.right)+"입니다.");
	}
	
	public int avg() {
		return (this.left + this.right)/2;
	}
	
	public void substract() {
		System.out.println(this.left - this.right);
	}
}

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

이것은 아래와 같은 에러를 발생한다.

Exception in thread "main" java.lang.Error: Unresolved compilation problem: 
    The return type is incompatible with Calculator.avg()

	at org.opentutorials.javatutorials.overriding.example1.SubstractionableCalculator.avg(CalculatorDemo.java:26)
	at org.opentutorials.javatutorials.overriding.example1.CalculatorDemo.main(CalculatorDemo.java:40)

overriding을 하기 위해서는 메소드의 리턴 형식이 같아야 한다. 즉 클래스 Calculator의 메소드 avg는 리턴 타입이 void이다. 그런데 이것을 상속한 클래스 SubstractionableCalculator의 리턴 타입은 int이다. 오버라이딩을 하기 위해서는 아래의 조건을 충족시켜야 한다.

  • 메소드의 이름
  • 메소드 매개변수의 숫자와 데이터 타입 그리고 순서
  • 메소드의 리턴 타입

위와 같이 메소드의 형태를 정의하는 사항들을 통털어서 메소드의 서명(signature)라고 한다. 즉 위의 에러는 메소드들 간의 서명이 달라서 발생한 문제다. 아래와 같이 상위 클래스의 코드를 변경해서 이 문제를 우회하자.

package org.opentutorials.javatutorials.overriding.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 int avg() {
		return ((this.left + this.right) / 2);
	}
}

class SubstractionableCalculator extends Calculator {
	
	public void sum() {
		System.out.println("실행 결과는 " +(this.left + this.right)+"입니다.");
	}
	
	public int avg() {
		return ((this.left + this.right) / 2);
	}
	
	public void substract() {
		System.out.println(this.left - this.right);
	}
}

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

차이점은 아래와 같다.

상위 클래스와 하위 클래스의 서명이 같기 때문에 메소드 오버라이딩을 할 수 있었다. 그런데 위의 코드를 보면 중복이 발생했다. 메소드 avg의 부모와 자식 클래스가 같은 로직을 가지고 있다. 중복은 제거 되어야 한다. 생성자와 마찬가지로 super를 사용하면 이 문제를 해결 할 수 있다.

package org.opentutorials.javatutorials.overriding.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 int avg() {
		return ((this.left + this.right) / 2);
	}
}

class SubstractionableCalculator extends Calculator {
	
	public void sum() {
		System.out.println("실행 결과는 " +(this.left + this.right)+"입니다.");
	}
	
	public int avg() {
		return super.avg();
	}
	
	public void substract() {
		System.out.println(this.left - this.right);
	}
}

public class CalculatorDemo {
	public static void main(String[] args) {
		SubstractionableCalculator c1 = new SubstractionableCalculator();
		c1.setOprands(10, 20);
		c1.sum();
		System.out.println("실행 결과는" + c1.avg());
		c1.substract();
	}
}

차이점은 아래와 같다.

하위 클래스의 메소드 avg에서 상위 클래스의 메소드를 호출하기 위해서 super를 사용하고 있다. 덕분에 코드의 중복을 제거 할 수 있었다.

이렇게해서 부모 클래스의 기능을 변경 할 수 있는 방법인 메소드 오버라이딩에 대해서 알아봤다.

댓글

댓글 본문
  1. 혹시 avg() 부분에서 return값을 수정하고 싶으면 어떻게 해야하나요..?

    부모 클래스에서 avg()리턴값을 받는 것이아니라 자식 클래스에서 재정의하고싶을때 어떻게 할수있을까요?
    아니면 재정의 할 필요가 없을까요?
  2. 서달
    20230323
  3. wwwqiqi
    완료
  4. MelonMusk
    09/04
  5. 람보
    2022.9.2
  6. 치키티타
    220811
  7. 너굴
    220810
  8. 김경모
    220623
  9. PassionOfStudy
    복습 2일차!
  10. 김은희
    20220610 완료
    오버라이딩 부모에게 상속받은 걸 재정의
    부모의 메소드의 형식과 자식의 리턴 데이터타입 ,이름 매개변수가 일치해야 오버라이딩 할 수 있다

    메소드 이름
    메소드 매개변수의 숫자와 데이터 타입 그리고 순서
    메소드의 리턴타입
  11. PassionOfStudy
    Overriding!
  12. 자바잡아
    22.05.03 오버라이딩 완료
  13. 20220426
  14. dogchang
    overriding의 정의는 알거같으나 여기서 설명한 제약사항이 전부는 아닌듯함.(네이버검색결과)

    super.xxx(); 의 활용방법을 좀더 찾아봐야할거같음. 부모클래스의 메소드를 참조한다는것외에 활용방법을 아직 모르겠음.

    2022.04.04 영상 시청 완료.
  15. aesop0207
    220329 Tue.
  16. java자바라
    마지막에 상위클래스와 하위클래스의 메소드가 같을때
    super키워드로 상위클래스 메소드를 불러와 중복을 제거하는데
    상위클래스와 하위클래스가 같은 메소드라면 하위클래스의 중복되는 메소드를 제거하고
    상위클래스에서 상속받아 사용하면 더 좋지 않을까요?
    나중에 상속받은 메소드에 추가하고 싶은기능이 생긴다면 추가할수 있나요?

    
  17. 모찌말랑카우
    22.02.15 완료
  18. aesop0207
    220207 Mon
  19. 민둥빈둥
    22.02.06
  20. 행달
    22.02.05 완료!
  21. 드림보이
    2021.12.09. overriding 파트 수강완료
  22. syh712
    2021-12-06
    <오버라이딩: 재정의>
    - 상속과 밀접한 관련.
    - 하위 클래스는 상위 클래스의 메소드를 주어진 그대로 사용해야 할까? 만약 그래야 한다면 제약이 상당할 것이다. 이런 제약을 벗어나려면 하위 클래스가 부모 클래스의 기본적인 동작방법을 변경할 수 있어야 한다. 이런 맥락에서 도입된 기능이 메소드 오버라이딩(overriding)이다.
    - 하위 클래스 입장에서 부모 클래스란 말하자면 기본적인 동작 방법을 정의한 것이라고 생각할 수 있다. 하위 클래스에서 상의 클래스와 동일한 메소드를 정의하면 부모 클래스로부터 물려 받은 기본 동작 방법을 변경하는 효과를 갖게 된다. 기본동작은 폭넓게 적용되고, 예외적인 동작은 더 높은 우선순위를 갖게하고 있다. 이것은 공학에서 일반적으로 발견되는 규칙이다. 이것을 메소드 오버라이딩(overriding)이라고 한다.
    - overriding을 하기 위해서는 메소드의 리턴 형식이 같아야 한다. 즉 클래스 Calculator의 메소드 avg는 리턴 타입이 void이다. 그런데 이것을 상속한 클래스 SubstractionableCalculator의 리턴 타입은 int이다. 오버라이딩을 하기 위해서는 아래의 조건을 충족시켜야 한다.
    메소드의 이름
    메소드 매개변수의 숫자와 데이터 타입 그리고 순서
    메소드의 리턴 타입
    위와 같이 메소드의 형태를 정의하는 사항들을 통털어서 메소드의 서명(signature)라고 한다. 즉 위의 에러는 메소드들 간의 서명이 달라서 발생한 문제다.

    - 하위 클래스의 메소드 avg에서 상위 클래스의 메소드를 호출하기 위해서 super를 사용하고 있다. 덕분에 코드의 중복을 제거 할 수 있다.
  23. 네제가해냈습니다
    211117
  24. IaaS
    2021-11-02 수강완료

    전역변수를 지역변수에서 다시 지정할 경우 지역변수의 변수가 우선순위를 갖고있다.

    이와 같이 부모 클래스에서 선언한 메소드를 자식 클래스에서도 선언한다면 자식 클래스에서의 메소드가 우선순위가 있기때문에 자식 클래스의 메소드 결과값이 나온다.
  25. H4PPY
    1017
  26. 미NI언
    10.11 완료!
  27. 멋을아는남자
    오호~~ 잘 보고 갑니다. super에 대한 이해가 되어가고 있네요
  28. 베이스박
    2021.9.15 학습완료했습니다. 감사합니다.
  29. super1Nova
    210820
  30. 악어수장
    2021-5-13
  31. 된찌장개
    c1.avg()이 반환하는 값을 받아서 출력하는 겁니다. 출력문 안에서 메소드를 호출할 수 있습니다.
    대화보기
    • 하연주
      210208 완료
    • 김태현
      질문이 있습니다.
      이클립스 없이 동영상만 보고 있습니다.

      main 코드에

      System.out.println("실행 결과는" + c1.avg());

      는 무었인가요

      System.out.println() 안에 c1.avg()를 넣어도 호출 실행이 되나요
    • 김태현
      2차 공부완료

      오버라이딩

      부모
      public int avg() {
      return ((this.left + this.right) / 2);

      자식
      public int avg() {
      return ((this.left + this.right) / 2);

      그대로 100 갇게 복사해서 쓴다.
      약간이라도 다르면 에러

      자식
      public int avg() {
      return ((this.left + this.right) / 2);

      ~ 을
      public int avg() {
      return super.avg();

      super로 간결하게 쓸 수 있다
      자식 코드에 이어 소스를 추가할 수 있다
    • hvii
      20200811
    • EunSeok Kang
      잘보고갑니다!!!20200807
    • 김승민
      2020-04-10
      완료
      감사합니다~
    • 흐무
      텍스트 말고도 기능적인 로직을 더 추가할때도 필요하죠
      같은 타입이면 불러와서 쓰면 편리해요
      대화보기
      • akakro
        그럼 메소드오버라이딩의 조건이

        메소드 서명인
        1. 메소드의 이름
        2. 메소드 매개변수의 숫자와 데이터 타입 그리고 순서
        3. 메소드의 리턴 타입
        이기 때문에 하위 클래스의 메소드을 추가하여 상위 클래스의 특정메소드의 내용을 바꾸고 싶으면..

        > 상위클래스 메소드의 로직수정
        > 하위클래스는 추가 및 super을 사용
        이 되는데..

        그럼 로직을 수정하여 메소드의 내용을 바꾸고 싶으면
        하위 클래스 메소드를 수정하여 오버라이딩하지 않는 것이 더 효율적이지 않나요?

        오버라이딩을 통해 추가할 수 있는 내용은 텍스트뿐인 건가요..?
      • 우마우마우마
        2020.3.4
      • ENJOY
        2020 01 30 1215
      • park
        2/2영상에서 추가적인 내용을 넣고 싶으면 return super.avg(); 이후에 추가하라고 하셨는데 return을 만나면 그 메소드는 종료되지 않나요??
      • Jaden
        개발을 공부하는 사람들에게 질문은 언제나 환영아닐까요!? 질문에 대한 답변을 하면서도 공부를 할 수 있으니까요!
        말씀하신 대로 입니다. 그대로 똑같은 내용을 사용한다면 overriding하지 않아도 상관이없습니다. overriding 하지 않을시 부모클래스의 메소드와 동일한 방식으로 작동하는 메소드를 사용하기 때문입니다.

        영상은 overriding을 설명하고 다시 한번 super 를 상기시키기 위해 사용한 것으로 보입니다.

        덧붙여 만약에, 자식클래스에서 부모클래스의 메소드와 동작방식이 똑같지만 부가적인 동작이 필요할 경우, super를 사용할 수 도 있을 것 같습니다.
        대화보기
        • 워나
          2019/10/17 완료
        • 허공
          감사합니다!
        • PassionOfStudy
          191003(목) - (1)
          수강완료~
        • 이채
          그대로 똑같은 내용을 사용할 거라면 불필요하겠지만 부모 메소드를 super로 불러오고 자식 메소드에서 거기에 덧붙여서 추가적인 내용을 만들려면 필요하지 않을까요?? 평균을 구한 뒤에 그 평균을 가지고 또 새로운 식을 가공하고 싶을 수도 있으니까요.
          대화보기
          • 홍주호
            20190912 완료
          • 다나가
            190903 - 수강완료!!!!
          • doevery
            수강완료
          버전 관리
          egoing
          현재 버전
          선택 버전
          graphittie 자세히 보기