오버로딩(overloading)이란?
한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 '메서드 오버로딩' 또는 '오버로딩'이라고 한다. 가장 대표적인 예는 println메서드가 있다. printStream 클래스에는 어떤 종류의 매개변수를 지정해도 출력할 수 있도록 오버로딩된 println 메서드를 정의해놓고 있다.
오버로딩 조건
1. 메서드 이름이 같아야 한다.
2. 매개변수의 개수 또는 타입이 달라야 한다.
3. 반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 않는다.
오버로딩 예1)
int add(int a, int b) { return a+b; }
int add(int x, int y) { return x+y; }
=> 오버로딩이 아니다!
=> 왜? 위의 두 메서드는 매개변수의 이름만 다를 뿐 매개변수의 타입이 같기 때문에 오버로딩이 성립하지 않는다. 컴파일하면, 'add(int, int) is already defined(이미 같은 메서드가 정의되었다.)'라는 메시지가 나타날 것이다. (메서드 중복정의)
오버로딩 예2)
int add(int a, int b) { return a+b; }
long add(int a, int b) { return (long)a+b; }
=> 오버로딩이 아니다!
=> 왜? 리턴 타입만 다른 경우이며, 매개변수의 타입과 개수가 일치하기 때문에 오버로딩으로 간주되지 않는다.
오버로딩 예3)
long add(int a, long b) { return a+b; }
long add(long a, int b) { return a+b; }
=> 오버로딩이다!
=> 왜? 두 메서드 모두 int형과 long형 매개변수가 하나씩 선언되어 있지만, 서로 순서가 다른 경우이다. 이 경우에는 호출 시 매개변수의 값에 의해 호출될 메서드가 구분될 수 있으므로 중복된 메서드 정의가 아닌 오버로딩으로 간주한다.
하지만!! add(3, 3L)이 호출되면 첫 번째 메소드가, add(3L, 3)이 호출되면 두 번째 메소드가 호출되지만 add(3, 3)을 호출할 수 없다. 두 메서드 중 어느 메서드가 호출된 것인지 알 수 없기 때문에 메서드를 호출하는 곳에서 컴파일 에러가 발생한다!
오버로딩 장점
-> 오버로딩을 통해 여러 메서드들이 println 이라는 하나의 이름으로 정의될 수 있다면, println이라는 이름만으로 기억하기 쉽고 이름도 짧게 할 수 있어서 오류의 가능성을 줄일 수 있다. 그리고 메서드의 이름만 보고도 '이 메서드들을 이름이 같으니, 같은 기능을 하겠구나.' 라고 쉽게 예측할 수 있게 된다.
-> 메서드의 이름을 절약할 수 있다. 하나의 이름으로 여러 개의 메서드를 정의할 수 있으니, 메서드의 이름을 짓는데 고민을 덜 수 있는 동시에 사용되었어야 할 메서드 이름을 다른 메서드의 이름으로 사용할 수 있기 때문이다.
가변인자와 오버로딩
가변인자는 '타입... 변수명'과 같은 형식으로 선언하며, PrintStream 클래스의 printf()가 대표적인 예이다.
public PrintStream printf(String format, Object... args) { ... }
위와 같이 가변인자 외에도 매개변수가 더 있다면 가변인자를 매개변수 중에서 제일 마지막에 선언해야 한다. 그렇지 않으면, 컴파일 에러가 발생한다. 가변인자인지 아닌지를 구별할 방법이 없기 때문이다.
아래와 같이 매개변수의 개수를 다르게 해서 여러 개의 메서드를 작성할 때, 가변인자를 사용하면 메서드 하나로 간단히 대체할 수 있다.
String concatenate(String s1, String s2) { ... }
String concatenate(String s1, String s2, String s3) { ... }
String concatenate(String s1, String s2, String s3, String s4) { ... }
// 가변인자 사용할 시
String concatenate(String... str) { ... }
가변인자는 인자의 개수를 가변적으로 할 수 있다. 심지어는 인자가 아예 없어도 되고 배열도 인자가 될 수 있다. 가변인자는 내부적으로 배열을 이용하는 것이다. 그래서 가변인자가 선언된 메서드를 호출할 때마다 배열이 새로 생성된다.
*가변인자가 편리하지만, 이런 비효율이 숨어있으므로 꼭 필요한 경우에마 사용하자!
System.out.println(concatenate()); // 인자가 없음
System.out.println(concatenate("a")); // 인자가 하나
System.out.println(concatenate("a", "b")); // 인자가 둘
System.out.println(concatenate(new String[]{"A", "B"})); // 배열도 가능
가변인자를 오버로딩할 때 한 가지 주의할 점이 있다!
public class VarArgs {
public static void main(String[] args) {
String[] strArr = {"100", "200", "300"};
System.out.println(concatenate("", "100", "200", "300"));
System.out.println(concatenate("-", strArr));
System.out.println(concatenate(",", new String[]{"1","2","3"}));
System.out.println("["+concatenate(",", new String[0])+"]");
System.out.println("["+concatenate(",")+"]");
}
static String concatenate(String delim, String... args){
String result = "";
for (String str : args) {
result += str+delim;
}
return result;
}
/* static String concatenate(String... args){
return concatenate("", args);
}
*/
}
1. 배열 쓸 때 주의할 점
System.out.println(concatenate("", new String[]{"100", "200", "300"})); // OK
System.out.println(concatenate("", {"100", "200", "300"})); // X
아래 문장은 허용되지 않는다.
2. 오버로딩 주의할 점
위의 코드에서 주석을 해제하면 컴파일 에러가 발생한다. 두 오버로딩된 메서드가 구분되지 않아서 발생하는 것이다. 가능하면 가변인자를 사용한 메서드는 오버로딩하지 않는 것이 좋다.
[참고]
Java의 정석 3판 (남궁성 저)
'공부 > 자바' 카테고리의 다른 글
변수의 초기화 (0) | 2024.05.29 |
---|---|
생성자(Constructor) (0) | 2024.05.29 |
객체 지향 프로그래밍(OOP) (0) | 2024.05.28 |
배열 선언과 초기화 (0) | 2024.05.26 |
조건문과 반복문 (0) | 2024.05.25 |