본문 바로가기

프로그래밍/JAVA

[JAVA} 메서드 오버로딩(method overloading)

JAVA의 정석(2nd Edition) (남궁 성 著) 186p~190p 를 참조해 코드를 작성했으며

개인적인 공부 내용을 적은 것이므로 오류가 있을 수 있습니다.


1. 메서드 오버로딩이란?


같은 이름을 갖고 있지만, 서로 다른 매개변수 형식을 가지고 있는 메서드를 여러 개 정의하는 것.


loading은 물건을 싣는 것이다. 

over loading이면 과적해서 싣는 것이다.


보통 하나의 메서드로 하나의 기능만 구현해지만

하나의 메서드로 여러 기능을 구현하기 때문에 붙여진 이름이다.


2. 오버로딩의 조건


1. 메서드의 이름이 같아야 한다. (위 예제는 add)

2. 메서드의 리턴타입이 다른 경우는 오버로딩이 성립되지 않는다. ( 위 예제는 int )

3. 매개변수의 개수 or 매개변수의 자료형이 달라야 한다. ( 위 예제는 개수는 같지만 타입이 다름 )


쉽게 생각하면, 오버로딩은 다양한 개성을 불어넣는 것이다.

리턴타입이 뒤죽박죽이여도 되고, 다양한 매개변수를 통해 개성을 준다.

하지만 "메서드의 이름"은 같아야 한다.



매개변수의 이름이 다른 경우에는 역시 메서드 오버로딩이 성립되지 않는다.

매개변수의 이름이라는 것은 결국 메서드 내부에서 의미가 있는 것이지, 

호출되는 단계에서는 매개변수의 이름을 고려하지 않는다.  따라서 어떤 메서드를 사용하려는 것인지

자바는 어떤 메서드를 이용해야 할지 알 리가 없다.


3. 오버로딩의 예


overloading : '동일한 이름'으로 다양한 매개변수와 다양한 리턴타입의 여러 메소드를 정의하는 것



int add(int a, int b) {return a+b;}
int add(int x, int y) {return x+y;}

두 메서드의 매개변수 이름이 다르지만(a,b 와 x,y) 매개변수 타입이 같아 오버로딩이 불가능하다. 

결론 : 매개변수 이름은 오버로딩에 영향을 주지 못한다. ( a ↔ x, b ↔ y )

    매개변수 타입이 달랴야 함. ( int 와 int ) or 매개변수 개수가 달라야 함.

int add(int a, int b) {return a+b;}
long add(int a, int b) {return (long)(a+b);}

매개변수는 같지만, 리턴타입이 다르다. (int와 long)

결론 : 리턴타입은 오버로딩에 영향을 주지 못한다!

1. int add(int a, long b) {return a+b;}
2. int add(long a, int b) {return a+b;}

위 예제는 매개변수 개수와 타입이 같지만, 순서가 다르게 되어있어서 오버로딩으로 간주한다.


결론 : 매개변수 이름과 리턴타입은 오버로딩과 상관이 없고 (아래 예제를 유심히 보시라)

신경써야 하는 부분은 매개변수 타입 or 매개변수 개수가 달라야 한다.



[ 문 제 ] add 메서드를 올바르게 오버로딩 한 것은? (자바의 정석 연습문제 6-13)

long add(int a, int b) { return a+b;} 


a. long add(int x, int y) { return x+y;}

b. long add(long a, long b) { return a+b;}

c. int add(byte a, byte b) { return a+b;}

d. int add(long a, int b) { return (int)(a+b);}



정답은 b,c,d, 이다. 리턴타입은 거들떠도 보지 말자. (리턴타입은 영향을 끼치지 못한다.)

매개변수 타입과 매개변수 개수가 다른지 보자.



[ 예제 1 ]


좀 더 큰 틀의 예제를 보도록 하자.



class MyMath {

int first, second, third;

public void a(int first, int second){
System.out.println("a(int first, int second)");
this.first = first;
this.second = second;
}

public void a(int first, int second, int third){
System.out.println("a(int first, int second, int third)");
this.first = first;
this.second = second;
this.third = third;
}

public void sum(){
System.out.println(this.first+this.second+this.third);
}
}


class exercise {
public static void main (String[] args){

MyMath mission = new MyMath();

mission.a(1, 2);
mission.sum();

mission.a(1, 2, 3);
mission.sum();


}
}

MyMath 클래스를 살펴보면, public void a라는 메서드가 중복 정의되어 있지만,

매개변수 개수를 달리함으로써 "중복 정의"하고 있다. 이를 오버로딩이라고 한다. (상속과는 관련 없음)

하지만 위 코드는 개선의 여지가 있다.


오버로딩 된 부분의 코드를

this.a(first, second)로 바꾸도록 한다.


[ 예제 2 : 상속과 오버로딩 ]


상속 관계에서도 오버로딩 사용이 가능하다.





4. 오버로딩의 장점


간단하게 생각하자. 하나의 이름으로 정의할 수 있다면 기억하기도 쉽고 

메서드의 이름도 절약이 가능해 오류를 줄일 수 있다.


void println()

void printlnBoolean (boolean x)

void printlnChar (char x)

void printlnDouble (double x)

void printlnString (String x)


매개변수에 따라 메서드의 이름을 다르게 해야 한다면 "낭비"이다.


5. 오버로딩 vs 오버라이딩


overriding : 부모클래스의 메소드를 자식클래스에서 '재정의'하여 사용합니다.  

    부모클래스 메소드의 내부로직을 아예 바꾸거나 로직을 추가할 때 사용합니다. 

이때의 규칙은 메소드의 이름과 매개변수의 개수, 데이터타입, 순서와 리턴 타입이 같아야합니다.


overloading : '동일한 이름'으로 다양한 매개변수와 다양한 리턴타입의 여러 메소드를 정의하는 것입니다.

라이딩과 로딩을 구분하는 쉬운 방법은 매개변수로 확인하는 것 입니다. 

매개변수가 같은데 내부 로직이 다르면 그것은 라이딩이고 매개변수가 다르면 무조건 로딩입니다.


<출처 : https://opentutorials.org/module/516/6088 >



6. 나의 시행착오


class MyMath {

int first, second, third;

public void a(int first, int second){
System.out.println("a(int first, int second)");
this.first = first;
this.second = second;
}

public void a(int first, int second, int third){
System.out.println("a(int first, int second, int third)");
this.first = first;
this.second = second;
this.third = third;
}

public void sum(){
System.out.println(this.first+this.second+this.third);
}
}


class exercise {
public static void main (String[] args){

MyMath mission = new MyMath();

mission.a(1, 2, 3);
mission.sum();

mission.a(1, 2);
mission.sum();

}
}

매개변수가 3개 전달되는 메서드가 매개변수 2개 전달되는 메서드에 영향을 미쳐서 결과값이 나온다.


매개변수가 3개인 메서드가 먼저 호출되면 아래 결과값이 3이 나와야 하는데, 6이 나오게 된다.


메서드 호출순서를 바꿔주니까 정상적으로 출력되는데 이유가 무엇일까?