Java

overriding

토픽 Java

창의적인 상속

상속은 상위 클래스의 기능을 하위 클래스에게 물려주는 기능이다. 그렇다면 하위 클래스는 상위 클래스의 메소드를 주어진 그대로 사용해야 할까? 만약 그래야 한다면 제약이 상당할 것이다. 이런 제약을 벗어나려면 하위 클래스가 부모 클래스의 기본적인 동작방법을 변경할 수 있어야 한다. 이런 맥락에서 도입된 기능이 메소드 오버라이딩(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. 24.01.19 완료
  2. Sansol Park
    네, 당연히 가능합니다. 부모 클래스에서 정의된 메소드를 자식 클래스에서 재정의(오버라이딩)하는 것은 객체 지향 프로그래밍의 주요 개념 중 하나입니다.

    자식 클래스에서 avg() 메소드를 재정의하려면, 부모 클래스에서 정의한 avg() 메소드와 동일한 메소드 시그니처(메소드 이름, 매개변수의 타입과 개수)를 가지면서 원하는 방식으로 구현하면 됩니다.

    예를 들어, 부모 클래스에서 avg() 메소드의 리턴 값이 두 숫자의 평균값이었다면, 자식 클래스에서는 이를 두 숫자의 중앙값을 리턴하도록 재정의할 수 있습니다.

    다음은 이에 대한 코드 예시입니다:

    class SubstractionableCalculator extends Calculator {
    //...
    @Override
    public int avg() {
    // 원하는 방식으로 메소드 재정의
    }
    //...
    }

    '@Override' 어노테이션은 해당 메소드가 부모 클래스의 메소드를 오버라이딩 한다는 것을 나타내며, 컴파일러에게 오버라이딩의 정확성을 체크하도록 지시합니다. 이는 선택사항이지만, 코드의 가독성과 안정성을 높이는 데 도움이 됩니다.

    재정의의 필요성은 전적으로 여러분의 비즈니스 로직과 설계에 따라 달라집니다. 부모 클래스의 메소드가 자식 클래스의 요구사항을 충족시키지 못하는 경우에만 메소드를 재정의해야 합니다. 그렇지 않다면, 재정의 없이 부모 클래스의 메소드를 그대로 사용할 수 있습니다. 이는 코드의 중복을 방지하고 유지 관리를 용이하게 하는 데 도움이 됩니다.

    GPT-4의 답변입니다. :)
    대화보기
    • 혹시 avg() 부분에서 return값을 수정하고 싶으면 어떻게 해야하나요..?

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

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

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

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

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

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

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

      이와 같이 부모 클래스에서 선언한 메소드를 자식 클래스에서도 선언한다면 자식 클래스에서의 메소드가 우선순위가 있기때문에 자식 클래스의 메소드 결과값이 나온다.
    • H4PPY
      1017
    • 미NI언
      10.11 완료!
    • 멋을아는남자
      오호~~ 잘 보고 갑니다. super에 대한 이해가 되어가고 있네요
    • 베이스박
      2021.9.15 학습완료했습니다. 감사합니다.
    • super1Nova
      210820
    • 악어수장
      2021-5-13
    • 된찌장개
      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 완료