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. 이번 강의 제일 하단 보충수업 예제에서 질문하신 방법에 대한 내용이 있네요. For each 구문 사용해서 total값을 배열길이로 나눠주는 방법이요.
    대화보기
    • 강의 잘 보고 있습니다. 감사합니다. 근데 여긴 질문을 해도 답은 없네요..
      (아무나 읽으신 분 중에 답 좀 부탁합니다~)
      첫번쨰 강의에서 setOprands의 매개변수 개수가 2개,3개일때마다
      avg()에서 나눠줄 숫자가 각각 2,3으로 변경되어야 결과적으로도 문제없는 '
      코드가 아닌가 합니다.. 그럼 2,3이 들어갈 부분은 어떻게 처리해줘야 하는지
      아시는 분 계신가요?
    • 배경지식이 전혀 없는 일반인이 수업을 듣기에는 개념을 정립하기가 참 헷갈리는 부분이 맞네요
      밑에 댓글 단 분들이 잘못된 부분을 알려주셔서 참고하면서 개념을 재정립해봤어요
      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은 '동일한 이름'으로 다양한 매개변수와 다양한 리턴타입의 여러 메소드를 정의하는 것입니다.
        라이딩과 로딩을 구분하는 쉬운 방법은 매개변수로 확인하는 것 입니다. 매개변수가 같은데 내부 로직이 다르면 그것은 라이딩이고 매개변수가 다르면 그것은 무조건 로딩입니다.
      • 감사합니다
      • 레니타키
        감사합니다
      • 오빠는다르다
        감사합니다!!!!
      • 첫번째 동영상 끝부분에
        동일 이름의 메소드가 매개변수 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
        처음 할때보다 갈수록 봤어요가 줄어드네요. 완강 해보겠습니다.
      • 오버로딩은 실제 코딩시에 많이 사용됩니다. 메소드명이 같다고 해서 나쁜 코딩이 아닙니다. 인풋인자에 따라 리턴값 또는 내부로직을 달리하기 위함입니다.
        대화보기
        • 객체주의극혐
          좋은 프로그래머는 메소드를 같은 이름, 즉 중복으로 사용하지않는것으로 알고있습니다.
          같은 이름이 아닌 프로그램을 만드는것이 좋은 프로그램이라고 합니다.
        • 박첩구드
          라이딩,로딩 정말 햇갈리네용~ㅠ 감사합니다!
        • 기초에 충실하자
          오버로딩의 리턴타입은 상관없는걸로 알고 있습니다.
        • 허허허헛ㅎ
          궁금한 점이 있습니다. 생성자 강의에 보면 생성자오류를 막기 위해서 생성자를 하나 더 만들게 됩니다. 이 것도 오버로딩에 속하는게 맞는 거죠?
        • 이병학
          ㅎㅎㅎ 아직 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배열을 정의해 준겁니다.
                    대화보기
                    • 왕초보
                      CalculatorDemo에서 int left, right, third = 0; 이렇게 해도 되여?
                      초보중의 초보, 대왕초보입니다.
                    • egoing
                      배열 객체를 만들기 위해서 new를 사용했습니다.
                      아래의 코드는 원소로 10, 20, 30을 갖는 배열을 만들어서 그것을 인자로 전달하고 있는 것이죠.
                      new int[]{10,20,30}
                      대화보기
                      • 이진혁
                        보충수업에서
                        c1.setOprands(new int[]{10,20});
                        이부분에 new를 써야 하는 이유가 무엇인가요??
                      • 샤핀
                        엇, 알고 보니 제가 short의 S를 대문자로 타이핑해서 오타로 인해 분기점을 타지 않았던 것이었습니다.
                        답변 감사합니다. 오랜 만에 다시 보게 되었습니다.
                        대화보기
                        • jeyul
                          샤핀님, 메소드 A의 매개변수의 데이터 타입을 short로 기술 하시면 돼요.
                          대신에 Short 클래스를 이용하시려면 메소드를 호출할때 Short 클래스의 인스턴스를 생성해서
                          인자로 넘겨 주시면 됩니다.

                          // 메소드 정의
                          void A(short arg1) { System.out.println("A(short arg1)"); }
                          void A(Short arg1) { System.out.println("A(class Short arg1)"); }

                          // 메소드 호출
                          od.A( (short)1 );
                          od.A( Short.valueOf((short)1) );
                          대화보기
                          • egoing
                            제가 예제를 잘못 만들어서 그렇습니다. 그 부분은 무시해주세요 :)
                            대화보기
                            • 마PD
                              제가 이해를 잘못한건지.. ㅠ.ㅠ
                              첫번째 소스 예제에서 매개변수가 2개이거나 3개이거나 avg(); 로 연산하면 3으로 나눠주고 있습니다..
                              변수가 3개짜리인 부분은 문제가 없을거 같은데 2개일때는 문제가 되지 않나요??

                              제가 잘못한건지 모르겠지만 고대로 복사해서 이클립스에서 돌리면 결과값이 현재 페이지에 나와 있는 것과는 다르게 나오네요..
                            • 도로시
                              첫 번째 동영상의 예제에서 인자를 10, 20 두 개만 주는 경우여도
                              public void avg(){
                              System.out.println((this.left+this.right+this.third)/3);
                              }
                              이 메소드로 인해 c1.avg의 값이 15가 아니라 10이 나옵니다..

                              overloading을 배운다는 목적으로 보면 중요한 부분은 아니지만
                              텍스트 설명으로 보면 15로 제대로 출력되는 것처럼 보여서 헷갈릴 수 있을 것 같아서요 ^^
                            • 샤핀
                              오버로딩 중에 정수형 중에 short형으로도 오버로딩을 하고 출력을 해봤는데 명시적 형변환을 써도 short메소드를 안 거치고 int 메소드 출력이 되던데... 혹시 제가 원하는 "void A (short arg1)" 이부분이 나오게 할 순 없을까요?
                              예를 들어 float형일 경우엔 3.0f 와 같이 구분을 해주면 되던데.. short도 첨자 같은 걸 달아주면 될려나 봤는데 short는 딱히 이런 첨자도 따로 없어 보여서요 ^^;;
                              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()");}
                              void A (Short arg1){System.out.println("void A (short arg1)");} <--- 이부분
                              public static void main(String[] args) {
                              OverloadingDemo od = new OverloadingDemo();
                              od.A();
                              od.A(1);
                              od.A("coding everybody");
                              od.A((short)2); <-- short 명시적 형변환
                              }
                              }
                            • 감사해요 :D
                              이렇게 빠르게 피드백을 해 주시다니, 놀랍고 감사합니다.
                              덕분에 많이 배우고 있습니다.
                              앞으로도 좋은 강의 부탁드립니다 :D
                            • egoing
                              보충수업의 내용을 추가했습니다.
                              대화보기
                              • egoing
                                좋은 지적 감사합니다. 지금 보니까 예제가 참 별로군요. 다형성이라는 것을 기존의 Calculator 예제에 맞춰서 설명하다보니까 생긴 문제 같습니다. 우선 내용은 3으로 변경했습니다. 그리고 문의 주신 내용은 추후에 수업으로 추가하도록 할께요. 그 전까지는 아래 문서를 참고해주세요. 피드백 감사합니다.

                                https://today.java.net......nts
                                대화보기
                                • 감사해요
                                  이 단계에서 중요한건 이게 아닌 것 같긴 합니다만,
                                  public void avg(){
                                  System.out.println((this.left+this.right+this.third)/2);
                                  여기서 평균은 변수가 세개니까 /3이 되어야 할 것 같아서요.
                                  그리고 변수가 네개로 늘어나면 /4가 되어야 하는데
                                  저 숫자 부분을 자동으로 지정 할 수 있는건 언제쯤 배우나요??
                                • egoing
                                  고쳤습니다 :)
                                  대화보기
                                  • egoing
                                    수정했습니다. 알려주셔서 감사합니다 ^^
                                    대화보기
                                    • 밑에 제트님 말처럼 3행은 오버로딩이고, 4행이 오버라이딩이네요..^^
                                      대화보기
                                      버전 관리
                                      egoing
                                      현재 버전
                                      선택 버전
                                      graphittie 자세히 보기