이전 게시물에서 객체의 주요 구성원인 멤버 메서드에 대해 알아 보았다. 이 게시물에서는 메서드의 주요 개념 중 하나인 메서드 오버로딩에 대해 알아보고자 한다.
메서드 오버로딩을 공부하기에 앞서 한 가지 알아야 할 개념이 있다.
바로 '접근 제한자(지정자)'이다.

접근 제한자는 4가지 종류가 존재하며 우리에게 가장 익숙한 public 외에도 protected, default(따로 표기하지 않음), private이 있다. 앞으로 자주 등장해 자연스럽게 익히게 될 개념이니 우선 각 제한자의 허용 범위가 어느 정도인지 간단하게만 기억을 해두자.
메서드 오버로딩은 하나의 클래스 내에서 같은 이름을 가지는 메서드가 여러 개 정의되는 것으로, 기억 및 메서드의 사용을 용이하게 하기 위해 같은 기능을 하는 메서드에 같은 명칭을 부여하기로 한 것이 그 목적이다.
다음은 메서드 오버로딩 조건이다.

① 앞서 배운 접근제한자는 달라질 수 있고,
② 반환형(void/return값)도 달라질 수 있으며
③ 메서드 명은 반드시 동일하고
④ 메서드에 전달되는 인자의 자료형, 개수 또는 배치된 순서가 반드시 달라야 한다.
예제를 통해 자세히 알아보자.
package kr.s12.object.overloading;
public class OverloadingMain01 {
public void print(int n) {
System.out.println("정수 n = " + n);
}
public void print(double a) {
System.out.println("실수 a = " + a);
}
public void print(double a, long b) {
System.out.println("실수 a = " + a + ", 정수 b = " + b);
}
public void print(long a, double b) {
System.out.println("정수 a = " + a + ", 실수 b = " + b);
}
public static void main(String[] args) {
OverloadingMain01 om = new OverloadingMain01();
om.print(20);
om.print(10.5);
om.print(8.7, 208L);
om.print(402L, 2.08);
}
}
제일 처음 print라는 이름을 가진 메서드를 생성하였고, int 자료형을 가지는 데이터(변수명 : n) 1개를 인자로 전달하였다.
자료형 차이 : 그리고 두 번째 print 메서드는 double 자료형을 가지는 데이터(변수명 : a) 1개를 인자로 전달하였기 때문에 메서드 오버로딩으로 인정되었고 충돌이 발생하지 않았다.만일 이때, public void print(int a){로 동일한 int 타입의 변수명만 다른 데이터 1개를 인자로 전달하였다면 어땠을까?

위와 같이 충돌한다. 이를 통해 알 수 있듯이, 변수명이 달라지는 건 중복 정의 조건에 해당하지 않는다.
개수 차이 : 세 번째 print 메서드는 double 자료형을 가지는 데이터가 있지만 long 자료형을 가지는 데이터 1개가 더 인자로 전달되어 두 번째 print 메서드와 인자 개수가 달라 메서드 오버로딩으로 인정되었고 충돌이 발생하지 않았다.
순서 차이 : 네 번째 print 메서드는 세 번째 print 메서드와 마찬가지로 long 자료형 데이터와 double 자료형 데이터를 인자로 갖지만, 그 순서가 다르다. 따라서 메서드 오버로딩으로 인정되었고 충돌이 발생하지 않았다.
따라서 OverloadingMain01 객체를 생성, 각 메서드를 호출한 결과는 다음과 같다.
출력)
정수 n = 20
실수 a = 10.5
실수 a = 8.7, 정수 b = 208
정수 a = 402, 실수 b = 2.08
이러한 메서드 오버로딩은 java의 다양한 패키지에 존재하는 메서드에도 적용된다.
다음은 String.valueOf() 메서드를 오버로딩, 전달되는 인자의 타입을 모두 String으로 변환한 뒤 해당 문자열의 길이를 구하는 예제이다.
package kr.s12.object.overloading;
public class OverloadingMain02 {
public void getLength(int n) {
String s = String.valueOf(n);
getLength(s);
}
public void getLength(float n) {
String s = String.valueOf(n);
getLength(s);
}
public void getLength(String s) {
System.out.println(s + "의 길이: " + s.length());
}
public static void main(String[] args) {
OverloadingMain02 om = new OverloadingMain02();
om.getLength(10000);
om.getLength(2.08f);
om.getLength("Hello");
}
}
가장 먼저 알아야 할 개념은 문자열(String)에는 길이가 존재한다는 것이다.
문자열은 이름에서도 유추할 수 있듯, 문자의 배열(char[])을 가공한 것이다. 그렇기 때문에 각각의 문자마다 인덱스가 존재하며, length()를 통해 길이를 구할 수 있다. (String이 기본 자료형이 아닌 '참조 자료형'에 해당했던 이유도 이 때문이다.)

따라서 첫 번째 getLength() 메서드는 인자로 int 자료형의 데이터를 전달 받아, String.valueOf() 메서드에 전달한 뒤,
String 타입으로 변환된 데이터의 길이를 length() 메서드를 통해 구한 다음 출력한다.
두 번째 getLength() 메서드는 인자로 float 자료형의 데이터를 전달 받아, String.valueOf() 메서드에 전달하고
String 타입의 데이터의 길이를 length() 메서드를 통해 구한 다음 출력한다.
그리고 마지막 getLength() 메서드는 String 타입의 데이터를 인자로 전달받아 따로 타입을 변환할 필요 없이
length() 메서드를 통해 길이를 구한 다음 출력한다.
이때, System.out.println(s + "의 길이: " + s.length());의 과정이 동일하게 반복되는데 만약 첫 번째, 두 번째 getLength() 메서드에 위 코드를 동일하게 반복해 작성했다면 이는 좋은 코드가 아니다.
예제와 같이 메서드 안에서 다른 메서드를 호출하는 방식으로 재활용성을 높이는 것이 좋다.
getLength() 메서드 안에 세 번째 getLength(s); 메서드를 호출, 변환한 String 데이터를 넘겨 다음과 같이 출력하였다.출력)
10000의 길이: 5
2.08의 길이: 4
Hello의 길이: 5
이 메서드 오버로딩(중복 정의)은, 이후에 배울 메서드 오버라이딩과 전혀 다른 개념이므로 그 정의 및 조건을 확실히 구분하여 알아둘 필요가 있다.