Java

overloading

계산기 예제로 돌아가보자. 우리의 계산기는 2개의 값(left, right)에 대한 연산(sum, avg) 만을 수행 할 수 있다. 그런데 만약 3개의 값을 대상으로 연산을 해야 한다면 어떻게 해야할까? 우선 아래와 같이 입력값을 3개 받아야 할 것이다. 

c1.setOprands(10, 20, 30);

이를 위해서 기존의 setOprands 메소드를 아래와 같은 모습을 수정한다면 2개의 입력값을 받을 수 없게 될 것이다.

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

이런 경우 아래와 같이 메소드의 이름을 변경하면 될 것이다.

c1.setOprands2(10, 20);
c1.setOprands3(10, 20, 30);

이것도 좋은 방법이지만 매개변수의 수에 따라서 메소드의 이름이 달라지는 것은 왠지 깔끔한 방법이 아닌 것 같다. 그럼 어떻게 해야 좋을까? 코드를 보자.

package org.opentutorials.javatutorials.overloading.example1;

class Calculator{
    int left, right;
    int third = 0;
     
    public void setOprands(int left, int right){
        System.out.println("setOprands(int left, int right)");
        this.left = left;
        this.right = right;
    }
    
    public void setOprands(int left, int right, int third){
        System.out.println("setOprands(int left, int right, int third)");
    	this.left = left;
        this.right = right;
        this.third = third;
    }
    
    public void sum(){
        System.out.println(this.left+this.right+this.third);
    }
     
    public void avg(){
        System.out.println((this.left+this.right+this.third)/3);
    }
}
 
public class CalculatorDemo {
     
    public static void main(String[] args) {
         
        Calculator c1 = new Calculator();
        c1.setOprands(10, 20);
        c1.sum();       
        c1.avg();
        c1.setOprands(10, 20, 30);
        c1.sum();       
        c1.avg();
        
    }
 
}

아래는 기본 예제와의 차이점이다.

실행 결과는 아래와 같다.

setOprands(int left, int right)
30
15
setOprands(int left, int right, int third)
60
30

아래 코드를 보자.

c1.setOprands(10,20); 

이 코드의 실행 결과는 화면에 아래와 같은 메시지를 출력한다.

setOprands(int left, int right)

다음 코드를 보자.

c1.setOprands(10, 20, 30);

실행 결과는 아래와 같다.

setOprands(int left, int right, int third)

이를 통해서 알 수 있는 것은 매개변수의 숫자에 따라서 같은 이름의, 서로 다른 메소드를 호출하고 있다는 것을 알 수 있다.

이름은 같지만 시그니처는 다른 메소드를 중복으로 선언 할 수 있는 방법을 메소드 오버로딩(overloading)이라고 한다.

오버로딩의 규칙

결론적으로 말하면 메소드 오버로딩은 매개변수를 사용한다. 즉 매개변수가 다르면 이름이 같아도 서로 다른 메소드가 되는 것이다. 반면에 매개변수는 같지만 리턴타입이 다르면 오류가 발생한다. 아래의 코드를 보자.

package org.opentutorials.javatutorials.overloading.example1;
public class OverloadingDemo {
    void A (){System.out.println("void A()");}
	void A (int arg1){System.out.println("void A (int arg1)");}
	void A (String arg1){System.out.println("void A (String arg1)");}
	//int A (){System.out.println("void A()");}
	public static void main(String[] args) {
		OverloadingDemo od = new OverloadingDemo();
		od.A();
		od.A(1);
		od.A("coding everybody");
	}
}

3행과 4행의 메소드 A는 매개변수의 숫자가 다르다. 4행과 5행의 메소드 A는 인자의 숫자는 같지만 매개변수의 데이터 타입이 다르다. 이런 경우는 오버로딩이 가능하다. 메소드를 호출 할 때 전달되는 인자의 데이터 타입에 따라서 어떤 메소드를 호출할지를 자바가 판단 할 수 있기 때문이다. 하지만 메소드의 반환값은 메소드를 호출하는 시점에서 전달되지 않는 정보이기 때문에 오버로딩의 대상이 될 수 없다.

상속과 오버로딩

상속의 관계에서도 오버로딩을 사용할 수 있을까? 물론이다. 

package org.opentutorials.javatutorials.overloading.example1;
public class OverloadingDemo2 extends OverloadingDemo{
    void A (String arg1, String arg2){System.out.println("sub class : void A (String arg1, String arg2)");}
	void A (){System.out.println("sub class : void A ()");}
	public static void main(String[] args) {
		OverloadingDemo2 od = new OverloadingDemo2();
		od.A();
		od.A(1);
		od.A("coding everybody");
		od.A("coding everybody", "coding everybody");
		
	}
}

실행 결과는 아래와 같다.

sub class : void A ()
void A (int arg1)
void A (String arg1)
sub class : void A (String arg1, String arg2)

클래스 OverloadingDemo2는 OverloadingDemo을 상속 받고 있다. OverloadingDemo2의 3행에서 정의된 메소드 A는 문자열을 데이터타입으로 하는 두개의 매개변수를 가지고 있다. 이러한 형태의 변수는 부모 클래스에서는 정의되어 있지 않기 때문에 메소드 오버로딩이 되는 것이다. 반면에 4행에서 정의된 메소드 A는 매개변수가 없다. 그리고 부모 클래스에는 이미 매개변수가 없는 메소드 A가 존재한다. 이 둘은 매개변수의 형태가 같기 때문에 오버로딩이 아니라 오버라이딩에 해당한다.

overriding VS overloading

오버라이딩과 오버로딩은 용어가 참으로 헷갈린다. 당연하다. 중요한 것은 오버라이딩이 무엇이고 오버로딩이 무엇인가를 구분하는 것은 아니다. riding(올라탄다)을 이용해서 부모 클래스의 메소드의 동작방법을 변경하고, loading을 이용해서 같은 이름, 다른 매개변수의 메소드들을 여러개 만들 수 있다는 사실을 아는 것이 중요하다. 다만 학습이나 협업의 과정에서 개념을 주고 받을 때는 용어가 중요해진다. 필자의 생각에 이 개념들이 헷갈리는 이유는 over라는 공통분모 때문이다. over를 제외하고 알아두면 덜 헷갈리지 않을까 싶다.

보충수업

위의 예제는 overloading을 설명하기 위한 예제일뿐 현실적이지 않다. 더 많은 값을 대상으로 연산을 해야 한다면 어떻게 해야할까? 아래와 같이 코드를 변경해보자.

package org.opentutorials.javatutorials.overloading.example1;

class Calculator{
    int[] oprands;
    
    public void setOprands(int[] oprands){
        this.oprands = oprands;
    }
    
    public void sum(){
        int total = 0;
        for(int value : this.oprands){
        	total += value;
        }
    	System.out.println(total);
    }
     
    public void avg(){
    	int total = 0;
        for(int value : this.oprands){
        	total += value;
        }
    	System.out.println(total/this.oprands.length);
    }
}
public class CalculatorDemo {
    public static void main(String[] args) {
    	Calculator c1 = new Calculator();
        c1.setOprands(new int[]{10,20});
        c1.sum();       
        c1.avg();
        c1.setOprands(new int[]{10,20,30});
        c1.sum();       
        c1.avg();   
    }
}

차이점은 아래와 같다.

위의 코드는 인자로 배열을 사용하고 있다. 이렇게하면 하나의 인자로 여러개의 값을 받을 수 있다.

댓글

댓글 본문
작성자
비밀번호
  1. ktg9114
    저 또한 보람차게님과 같은 생각이네요~~ ^^
    대화보기
    • 빛나는여름
      역시 개념이 어려워질수록 이상과 현실의 괴리가 중도포기를 불러오는 것 같네요 ㅋㅋㅋ
      언어소개는 조회수가 14만인데 이번 강의는 1.4만입니다.
      대화보기
      • yoon88
        완료/다시보기 어려움...
      • sealwind
        sum()과 avg()의 중복을 없애려면 이렇게 수정하면 어떤가요?

        public int sum() {
        int total = 0;
        for(int value : this.operands) {
        total += value;
        }
        return total;
        }
        public int avg() {
        return this.sum()/this.operands.length;
        }

        출력부분에 System.out.println 을 추가하구요~
      • 미림_likelion
        수강 완료했습니다. 감사합니다.
      • 이준열
        정리해주신 개념이 많이 도움됬어요 감사합니다!
        대화보기
        • 서영기
          안녕하세요, 생활코딩 강사님.
          오버로딩 두 번째 동영상 강좌에서 오버로딩과 오버라이딩의 개념의 차이를 설명하시려다가 조금의 혼동이 오신 거 같습니다.

          오버로딩의 조건을 설명하실 때 나온 오버로딩 시, 리턴값 타입 일치 여부는 상관없는 걸로 알고 있습니다. 위의 동영상 첫 번째 예제에서 에러가 나는데 그 에러 메시지는 "Duplicate method A() in type"으로 A()라는 메써드의 리턴타입이 아니라, 같은 메써드 타입을 중복 사용했기 때문이라고 알려주고 있습니다. 즉, 오버로딩은 이름이 같은 메써드의 서로 다른 타입의 매개변수를 덮어쓰기 위함인데, 매개변수 형식(시그니쳐)이 동일하면 오버로딩이 되지 않기 때문입니다. 위의 예제에서 A() 메써드 앞의 리턴값 타입 int를 void로 수정해도 빨간 줄은 계속 그여져 있고 실행값은 6행의 A() 메써드의 코딩내용이 그대로 출력됩니다. 컴파일 전에 에러가 표시되었는데도 불구하고 출력되는 까닭을 모르겠는데, 이것에 대한 답변 부탁드립니다.

          저는 오버라이딩과 오버로딩의 개념을 이렇게 잡았습니다. 오버라이딩은 메써드끼리의 메써드 내의 코딩 내용을 덮어쓰기를 위한 기능이며, 오버로딩은 메써드에 전달하는 매개변수의 형식(시그니쳐)를 덮어쓰기 위한 기능으로 구분했습니다. 그래서 이전의 메써드를 갈아 타는데(riding)는 메써드의 규정된 형식(매개변수 시그니쳐, 리턴 타입)이 모두 동일해야 이후의 새로 생성할 메써드 내의 코딩으로 덮어쓸 수 있으며, 매써드의 형식을 새롭게 부르기(loading) 위해서는 리턴 타입과 메써드 내의 코딩 내용과는 관계없이 단지 그 형식(매개변수와 인자)의 종류, 순서 그리고 개수가 달라야 하기 때문입니다.

          지금까지 오버로딩에 대해서 이 동영상을 보고 개념을 잡는 사람들은 전부 강사님의 말대로 개념을 잡을 수 있기 때문에 아래 댓글의 근거를 통해서도 확인을 해주시고 빠른 시일 내에 수정되었으면 합니다. 감사합니다.
        • J_Project
          오버로딩을 할 때, 동일해야하는 서명이 메소드의 이름과 메소드의 반환 타입이라고 했는데,
          메소드의 반환 타입이 달라도 실행이 되는 것을 확인했습니다.
          그렇다면 오버로딩을 할 때 동일해야 하는 서명은 메소드의 이름이라고 생각하면 될까요?
          대신 달라야하는 것은 인자의 데이터 타입 혹은 인자의 갯수 이고요.

          void A(){System.out.println("void A()");}
          void A(int arg1){System.out.println("void A(int arg1)");}
          void A(String arg1){System.out.println("void A(String arg1)");}
          int A(double arg1){System.out.println("void A(double arg1)");return 1;}
        • J_Project
          평균 값을 계산하는 메소드는 setOprands가 받는 인자에 따라 나누기를 다르게 해야하겠죠
          그래서 저는 클래스 변수 arg를 하나 정수로 정의해서
          setOprands가 실행될 때에 인자 수를 arg에 넣어서
          avg 메소드가 실행 될 때, arg의 값에 따라 다르게 나누기를 하도록 해보았습니다.

          class Calculator{
          int left, right, third;
          int arg;

          public void setOprands(int left, int right){
          System.out.println("setOprands(int left, int right)");
          this.left = left;
          this.right = right;
          arg=2;
          }

          public void setOprands(int left, int right, int third){
          System.out.println("setOprands(int left, int right, int third)");
          this.setOprands(left, right);
          this.third = third;
          arg=3;
          }

          public void avg(){
          if(arg==2){
          System.out.println((this.left+this.right)/2);
          }else if(arg==3){
          System.out.println((this.left+this.right+this.third)/3);
          }
          }
        • 김인섭
          감사합니다.
        • 첫 예제 실행 결과는 다음이 맞습니다.

          setOprands(int left, int right)
          30
          10
          setOprands(int left, int right, int third)
          60
          20
        • Braden
          그럼 기본 생성자 말고 생성자도 오버로딩이 가능한가요?
          가능하다면 인스턴스 생성할 때 매개변수에 따라서 초기화가 달라지게 만들수 있을거같은데요.
        • <span style="color:red; font-weight:bold">ㅎㅇㅎㅇ</span>
        • 강의가 진행될수록 봤어요 수가 줄어드는게 재미있네요ㅋㅋㅋ
        • public void avg(int two){
          System.out.println((this.left+this.right)/2);
          }

          public void avg(double three){
          System.out.println((this.left+this.right+this.third)/3);
          }

          저는 이런식으로 인트값과 더블값으로 나눠버려서 매개변수를 다르게 만들어서 표현해봤습니다.
          오버로딩은 매개변수를 다르게하는 것이니 저렇게 바꿔보았습니다.
          뭐 String이나 char도 상관없겠죠 여기선 매개변수를 다르게 하는게 중요한것이니.. 저도 초보인지라
          여기까지 배운 방법으로는 저게 맞지 않나 싶습니다 ㅎㅎ 도움이 되셨으면 하네요.

          Calculator c1 = new Calculator();
          c1.setOprands(10, 20);
          c1.sum();
          c1.avg(2);
          c1.setOprands(10, 20, 30);
          c1.sum();
          c1.avg(3.0);

          값이 2개일때엔 인트값을 줘버려서 avg(정수) -> ((this.left+this.right)/2); 실행되게하고

          값이 3개일때엔 더블값을 주면 avg(소수점) -> ((this.left+this.right+this.third)/3); 실행되게 해봤어요.
          대화보기
          • 라떼
            보충수업에 관한 강의도 필요한것 같습니다.ㅠ
          • skyn
            이번 강의 제일 하단 보충수업 예제에서 질문하신 방법에 대한 내용이 있네요. For each 구문 사용해서 total값을 배열길이로 나눠주는 방법이요.
            대화보기
            • eykim
              강의 잘 보고 있습니다. 감사합니다. 근데 여긴 질문을 해도 답은 없네요..
              (아무나 읽으신 분 중에 답 좀 부탁합니다~)
              첫번쨰 강의에서 setOprands의 매개변수 개수가 2개,3개일때마다
              avg()에서 나눠줄 숫자가 각각 2,3으로 변경되어야 결과적으로도 문제없는 '
              코드가 아닌가 합니다.. 그럼 2,3이 들어갈 부분은 어떻게 처리해줘야 하는지
              아시는 분 계신가요?
            • Sadak
              배경지식이 전혀 없는 일반인이 수업을 듣기에는 개념을 정립하기가 참 헷갈리는 부분이 맞네요
              밑에 댓글 단 분들이 잘못된 부분을 알려주셔서 참고하면서 개념을 재정립해봤어요
              egoing님이 영상에서는 오버라이딩이라고 언급하셨지만 텍스트 설명에는 오버로딩이라고 적어놓으셨기
              때문에 영상과 텍스트까지 꼼꼼하게 보신분은 그 차이점을 분명 아실 수 있을 거에요.


              두번째 영상의 OverlosdDemo2 의 내용입니다.

              <하위 클래스>
              3 void A (String arg1, String arg2){
              System.out.println("sub class : void A (String arg1, String arg2)");
              }
              <text 설명부분입니다.>
              3행에서 정의된 메소드 A는 문자열을 데이터타입으로 하는 두개의 매개변수를 가지고 있다.
              이러한 형태의 변수는 부모 클래스에서는 정의되어 있지 않기 때문에 메소드 오버로딩이 되는 것이다.




              void A (){
              System.out.println("sub class : void A ()");
              }
            • paskal kinar
              두 번 째 동영상 8:48 에 이고잉님의 발언 중 잘못된 게 있어 바로잡습니다.
              오버라이딩이라고 하시는데, 저 경우는 오버로딩입니다.

              메소드의 이름 같고, 매개변수의 형식(시그니처)이 다르기 때문에 '오버로딩'입니다.
            • 왕초보
              오타수정 ^^
              setOprands(int left, int right)
              30
              10
              setOprands(int left, int right, int third)
              60
              30
            • Weaver
              강의 잘 듣고 있습니다! 다만 오버로딩 부분 설명하실때는 살짝 실수하신 것 같네요.
              오버로딩의 리턴 타입은 달라도 상관없는 것 같습니다. 중요한 건 매개변수 숫자나 타입이 달라야만 하는 것이고..
            • joo0914krs
              감사합니다
            • JustStudy
              고맙습니다
            • 매우감사
              매우매우 감사합니다!! 너무 정리잘하셨네요!!
              대화보기
              • 김트라슈
                감사합니다
              • 보람차게
                영상을 보시면 중간에 이고잉님께서 오버로딩의 리턴타입은 같다라고 얼핏 말하시는데 아마 실수이신 것 같습니다.
              • 보람차게
                정리합니다.
                overriding은 부모클래스의 메소드를 자식클래스에서 '재정의'하여 사용합니다. 부모클래스 메소드의 내부로직을 아예 바꾸거나 로직을 추가할 때 사용합니다. 이때의 규칙은 메소드의 이름과 매개변수의 개수, 데이터타입, 순서와 리턴 타입이 같아야합니다.
                overloading은 '동일한 이름'으로 다양한 매개변수와 다양한 리턴타입의 여러 메소드를 정의하는 것입니다.
                라이딩과 로딩을 구분하는 쉬운 방법은 매개변수로 확인하는 것 입니다. 매개변수가 같은데 내부 로직이 다르면 그것은 라이딩이고 매개변수가 다르면 그것은 무조건 로딩입니다.
              • 감사합니다
              • 레니타키
                감사합니다
              • 오빠는다르다
                감사합니다!!!!
              • nadia
                첫번째 동영상 끝부분에
                동일 이름의 메소드가 매개변수 2개일 때와 3개일 때의 오버로딩을 설명하시면서,
                메소드 내용이 반복 기술되는 것을 피하기 위해
                두번째 메소드 내용 안에 첫번째 메소드를 호출하는 부분이 있는데요.

                public void setOprands(int left, int right){
                System.out.println("setOprands(int left, int right)");
                this.left = left;
                this.right = right;
                }

                public void setOprands(int left, int right, int third){
                this.set(left, right); <= 이부분
                System.out.println("setOprands(int left, int right, int third)");
                this.third = third;
                }

                이때 this.와 관련해 잘 이해가 되지 않는 점이 있어서요.

                1. 메소드를 호출할 때는 원래 그 메소드를 적용하는 인스턴스명을 앞에 꼭 붙여주는 건가요? (이를테면 c1.sum();처럼 써야하기 때문에 형식을 갖추기 위해 this.를 붙이는 건가요?)

                2. 처음에 잘 모르고 this.없이 set(left, right);만 썼었는데, 결과값은 같게 나오더라구요.
                위의 예에서 this.set(left, right);으로 썼을 때와 set(left, right);으로 썼을 때 의미는 어떻게 달라지나요?
              • 이바몬
                한 클라스 내에서 overloading 에 의한 두개의 생성자를 만들 수가 있나요?
              • panda_90
                처음 할때보다 갈수록 봤어요가 줄어드네요. 완강 해보겠습니다.
              • Alexa
                오버로딩은 실제 코딩시에 많이 사용됩니다. 메소드명이 같다고 해서 나쁜 코딩이 아닙니다. 인풋인자에 따라 리턴값 또는 내부로직을 달리하기 위함입니다.
                대화보기
                • 객체주의극혐
                  좋은 프로그래머는 메소드를 같은 이름, 즉 중복으로 사용하지않는것으로 알고있습니다.
                  같은 이름이 아닌 프로그램을 만드는것이 좋은 프로그램이라고 합니다.
                • 박첩구드
                  라이딩,로딩 정말 햇갈리네용~ㅠ 감사합니다!
                • 기초에 충실하자
                  오버로딩의 리턴타입은 상관없는걸로 알고 있습니다.
                • 허허허헛ㅎ
                  궁금한 점이 있습니다. 생성자 강의에 보면 생성자오류를 막기 위해서 생성자를 하나 더 만들게 됩니다. 이 것도 오버로딩에 속하는게 맞는 거죠?
                • 이병학
                  ㅎㅎㅎ 아직 java 언어가 괜히 복잡하고 산만한 것 같다는 생각이 자꾸만 들어요.
                  실제로 코딩에서 위의 상속이니 오버로딩???같은 것이 사용되는 지도 궁금하고 ...초보주제에 너무 진도가 많이 나간 것인 지 ...
                  실제프로그램을 해 봐야 왜 이런 것들이 필요한 지 알 수 있을 듯 싶네요.
                  잘 보고 갑니다.
                • cocohodu
                  좋은강의 감사합니다
                • urimago
                  답변 감사합니다!
                  대화보기
                  • 고르고나
                    매개변수의 타입과 갯수, 순서에 따라서 자바는 해당 메소드(이름이 같은)가 같은 것인지 다른 것인지 판단합니다.
                    즉, 이 부분이 같을 경우는 자바는 같은 메소드로 판단해버리죠.

                    리턴 타입의 경우는 실행된 이후에나 판단하게 됩니다.
                    매개변수가 같지만 리턴 타입이 다른 메소드를 선언했을 경우에 사용자가 그 중에 하나를 실행하고자 호출하면, 자바는 사용자가 어떤 리턴 타입으로 돌려줘야 하는지 알 수 없습니다. 호출하는 시점에서는요. 그래서 에러가 나지만, 매개변수가 다르다면 리턴 타입은 상관이 없습니다.

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

                    public int sum(int base) {
                    System.out.println(this.left + this.right + base);
                    return this.left + this.right + base;
                    }

                    public void sum(int left, int right) {
                    System.out.println(left + right);
                    }
                    대화보기
                    • urimago
                      오버로딩에 대한 질문이 있습니다. 중간에 내용을 잘못 이해해서, 오버로딩도 리턴타입이 무조건 같아야만 하는 줄로 오해를 하고 있었는데요. 인터넷을 찾아보다가 리턴타입은 상관 없다는 글들을 발견해서 강의를 다시봤습니다. 제가 이해한게 맞는지 확인좀 해주세요..

                      내용을 정리하면,, 같은 이름의 함수가
                      1. 리턴타입이 같고, 매개변수 개수나 타입이 다르다 : 오버로딩에 해당
                      2. 리턴타입이 다르고, 매개변수 개수나 타입이 같다 : 오류

                      인 것 같은데, 그러면
                      3. 리턴타입도 다르고, 매개변수 개수 및 타입도 다르다
                      도 오버로딩에 해당된다. 가 맞는 말인가요?
                    • for의 두가지 형식에 대해선 이곳에서 잘 설명되잇네요
                      http://01027921288.tistory.com......%B8

                      배열 전체의 값을 변수에 넣어 실행시키는 반복문이군요
                      대화보기
                      • 마르티엘
                        보충수업에 해당하는 강의가 올라와야 할 것 같습니다.

                        수업에서 배울수 없었던 내용들이 있어서 좀 난감합니다.

                        sum,avg의 메소드의 for문은 이전 반복문 수업시간에 없어서 이해가 안되구요...

                        매개변수로 배열 선언하는 방법도 저렇게 쓰셨으니 저게 규칙이겠지만 처음 보면 저게 규칙인지도 알기가 힘드네요....

                        이런 설명도 좀 올려주셨으면 좋았을거 같습니다.
                      • egoing
                        메소드가 속해있는 인스턴스(클래스가 아닌 객체)를 가르키는 말입니다.
                        대화보기
                        • 늘푸름
                          this. 에 대한 쓰임에 대해서 질문을 하고싶습니다. 첫번째 동영상 마지막부분보다가 궁금해진건데요. this.left 라고 쓰는경우는 객체의 전역변수를 수정할때 쓰인것이고, this.setOperands 는 메소드 자신을 가리키는 말인게 맞나요? this. 은 객체든 메소드든 자기자신을 가리키는 말이라고 이해하면 될까요?
                        • 초보
                          가능해요
                          대화보기
                          • 산적
                            배열을 매개변수로 취하고 있으니까요 int배열을 정의해 준겁니다.
                            대화보기
                            버전 관리
                            egoing
                            현재 버전
                            선택 버전
                            graphittie 자세히 보기