오버로딩(Overloading)이란?
한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것
기본적으로 메서드도 변수와 마찬가지로 같은 클래스 내에서 서로 구별될 수 있어야 하기 때문에 각기 다른 이름을 가져야 한다. 그러나 Java에서는 한 클래스 내에 같은 이름을 가진 메서드가 있더라도 매개변수의 개수 또는 타입이 다르면 다른 메서드로 취급할 수 있다.
오버로딩의 대표적인 예시는 'println()' 메서드이다. 콘솔에 데이터를 출력하기 위해 흔히 사용하는 가장 기초적인 메서드이지만, 사실 자세히 살펴보면 매개변수로 어떤 값이 들어오든 정상적으로 출력할 수 있도록 10개의 println 메서드가 오버로딩 되어있다.
오버로딩의 조건
위에서 언급했듯이 오버로딩이 성립하려면 두 가지 조건을 만족해야 한다.
1. 메서드의 이름이 같아야 한다.
2. 매개변수의 개수 또는 타입이 달라야 한다.
이 두 가지 조건을 모두 만족해야만 오버로딩으로 간주되고, 만약 둘 중 하나라도 어긴다면 컴파일 시에 에러가 발생한다. 추가로 오버로딩은 매개변수만 따질 뿐, 반환 타입은 아무 영향을 주지 못한다는 점을 기억해야 한다.
아래는 주의해야 할 몇 가지 예시 코드이다.
int add(int a, int b) // 매개변수의 이름이 다른 것만으로는 오버로딩이 되지 않는다
int add(int x, int y) // 에러
int add(int a, int b) // 반환 타입은 상관이 없다
long add(int a, int b) // 에러
long add(int a, long b) // 순서가 다른 경우는 매개변수가 다른 것으로 취급한다
long add(long a, int b) // 오버로딩
오버로딩의 장점
만약 오버로딩 기능이 없었다면, println()은 아래와 같은 상황이었을 것이다.
void println()
void printlnBoolean(boolean x)
void printlnChar(char x)
void printlnString(String s)
...
오버로딩은 위와 같이 같은 기능을 하는 메서드들을 같은 이름으로 묶음으로써, 개발자 입장에서는 이름을 짓는 수고를 덜 수 있고 사용자 입장에서는 기억해야 할 메서드가 줄어드는 효과를 볼 수 있다. 또한 여러 메서드를 하나의 이름으로 부르게 되면, 다른 메서드의 이름을 지을 때도 더 넓은 선택지에서 고를 수 있다는 장점도 있다.
가변인자와 오버로딩
가변인자(variable arguments)란?
가변인자(variable arguments)는 메서드에 들어올 수 있는 매개변수의 개수를 지정하지 않고 유동적으로 받을 수 있게 해주는 기능이다. 이때 가변인자가 받을 수 있는 값의 개수는 특별히 제한이 없다. 즉 0개부터 n까지 원하는대로 값을 넣어도 상관이 없으며, 심지어는 타입만 일치하면 배열도 넣을 수 있다.
가변인자는 '타입명... 변수명'과 같이 선언하며, 사용 방법은 아래와 같다.
// 들어오는 문자열을 전부 하나로 합쳐주는 메서드
String concatenate(String... args) {
String result = "";
for (int i = 0; i < args.length; i++) {
result += args[i];
}
return result;
}
위의 코드를 보면 가변인자는 내부적으로 배열을 이용한다는 사실을 눈치챌 수 있을 것이다.
가변인자가 선언된 메서드는 호출될 때마다 배열을 새로 생성하기 때문에, 편리하다고 남용하면 비용이 많이 들어 성능의 저하가 발생할 수 있으므로 주의해야 한다.
그리고 가변인자를 다른 매개변수와 함께 사용할 때도 주의가 필요하다.
String concatenate(String... args, String delim) {}
예를 들어 위의 코드는 컴파일 에러가 발생하는 코드이다. 왜냐하면 가변인자가 같은 타입의 매개변수 앞에 오면서 어디까지가 가변인자인지 구분할 수 없어졌기 때문이다.
때문에 Java에서는 항상 가변인자를 명확히 구분할 수 있도록 하기 위해 가변인자를 선언할 때는 반드시 가장 마지막에 선언하게 만들었다. 만약 가변인자의 뒤에 다른 매개변수가 선언되면 컴파일 에러가 발생한다.
가변인자 메서드 오버로딩
위와 비슷한 이유로 가변인자를 사용한 메서드를 오버로딩할 때는 반드시 주의해야 한다.
String concatenate(String delim, String... args) { }
// delim은 구분자를 의미하는 축약어이다.
String concatenate(String... args) { }
예를 들어 위의 두 메서드는 정상적으로 오버로딩 된 것처럼 보이지만, 컴파일 에러가 발생한다.
왜냐하면 컴파일러의 입장에서는 concatenate()의 첫 번째 인자로 들어오는 문자열이 가변인자를 의도한 것인지, 아니면 delim을 의미하는 것인지 알 수 없기 때문이다.
따라서 가능하면 가변인자를 사용한 메서드는 오버로딩을 피하는 것이 좋다.