[Java] 객체지향 프로그래밍 - 오버로딩

오버로딩(Overloading)

메서드도 변수와 마찬가지로 같은 클래스 내에서 서로 구별될 수 있어야 하기 때문에 각기 다른 이름을 가져야 해요. 하지만 한 '클래스' 내에서 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있어도 매개변수 개수 또는 타입이 다르면 같은 이름을 사용해서 정의가 가능해요. 이처럼 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 메서드 오버로딩Overloading, 또는 오버로딩Overloading이라 해요.

오버로딩은 개발자의 입장에서 메서드 명 표기에 고민을 하지 않게 해줘요. 매개변수 타입, 개수에 따라 이름을 달리 줘야한다면 일일히 명시해야 하는(그러면서도 메서드의 의도를 해하지 않는) 방식으로 개발을 해야해요.

int addInt(int a, int b);
int addLong(long a, long b);

적어도 해당 메서드를 만드는 개발자나 사용하는 개발자에게나 오버로딩은 매력적인 기능이에요.

여담으로 C언어 기반 API를 보면 오버로딩이 안되서 위 예제처럼 작성되어 있어요. 보시면 새삼 오버로딩의 중요성을 알게되요 ㅎㅎ.

오버로딩 조건

다음과 같은 조건이 성립해야 클래스 내에 동일한 이름의 메서드가 존재해요.

1. 메서드 이름이 같아야 해요
2. 매개변수의 개수 또는 타입이 달라야 해요

// 이렇게 반환 타입이 동일하고, 
// 인자(Argument) 개수나 타입이 다르면 오버로딩이 성립해요.
public void add(int a, int b);
public void add(int a, int b, int c);
public void add(long a, long b);

위 조건을 성립하지 못하면 오버로딩을 시도해도 중복된 정의라 하면서 컴파일 에러가 발생해요. 오버로딩된 메서드들은 매개변수에 의해서만 구별될 수 있기 때문에 반환 타입은 오버로딩을 구현하는데 영향을 주지 못해요.

// 반환 타입이 아니라서 둘을 오버로딩 대상이 아니라고 생각해서
// 컴파일 에러 처리되요!
public int add(int a, int b);
public long add(int a, int b, int c);

디테일하게 들어가기 위해 몇가지 조건을 더 넣어볼게요.

[조건 1] 인자 명만 다른 경우

public int add(int a, int b);
public int add(int x, int y);

변수명만 달라요. 인자의 타입과 개수가 일치하기 때문에 중복된 코드라 컴파일 에러 처리해요.

[조건 2] 타입이 다른 경우

public int add(int a, long b);
public int add(long a, int b);

인자의 타입이 다른 경우에요. 이 경우 컴파일하는데 문제는 없지만 사용하기 어려워요. 매개변수로 보낼 때 확실한 형선언이 필요해요. 애매한 선언은 모호한 코드라 하여 컴파일 에러 처리해요.

add(1, 3L);
add(1L, 3);
// add(1, 3);	// Error! 선언이 모호해요

[조건 3] 반환 값이 다른 경우

long add(int a, int b):
int add(int a, int b):

반환 타입이 다르기 때문에 둘은 오버로딩 대상이 아니에요. 그러니 메서드 명이 같아 컴파일 에러 처리해요.

[조건 4] 올바른 예

int add(int a, int b);
int add(long a, long b);
int add(int[] arr);

이처럼 반환 타입과 인자 타입과 개수가 확실히 구분된 경우에 정상적으로 오버로딩 되요.

가변인자(varargs)와 오버로딩

JDK 1.5버전부터 메서드의 매개변수를 동적으로 지정이 가능해졌어요. 이 기능을 가변인자varargs라고 해요. 선언 형식은 {타입}... 변수명이에요. 이때 주의할 점은 가변인자는 항상 매개변수 중 가장 마지막에 선언해야 해요. 그렇지 않으면 컴파일 에러가 발생해요. 가변인자인지 아닌지 구분할 수 없기 때문이에요.

// int add(int a);
// int add(int a, int b);
//int add(int a, int c);	// 요것들을...
int add(int... args); 	// 이거 하나로 대체!
// int add();				// 가변인자는 매개변수가 0개인 것도 대체해요
// int add(int... args, var sth); // Error!

가변인자는 다수의 매개변수 뿐만 아니라 배열로도 초기화가 가능해요.

int add(int[] a);
int add(int... a);

그러면 둘이 차이가 뭘까요? 배열이 매개변수인 경우는 설령 매개변수가 필요 없더라도 항상 명시적으로 매개변수에 선언을 해줘야 해요. 그런데 아까 언급했듯이 가변인자는 매개변수가 없는 경우도 처리하기 때문에 이럴 필요가 없어요.

add(null); add(new int[]{}); 	// 배열 매개변수는 반드시 명시해줘야 해요
add();							// 가변인자 매개변수는 이것도 성립해요!

그리고 방금 발견한 사실인데, 단일 변수와 배열 변수는 혼용해서 사용하면 컴파일 에러가 발생해요.

// 컴파일 에러!
// 도중에 배열 -> 단일 변수 안됨 
System.out.println(concatenate(",", new String[] {"1"}, "100"));
// 도중에 단일 변수 -> 배열 안됨
System.out.println(concatenate(",", "100", new String[] {"1"}));

그리고 이것도 안되요.

// 컴파일 에러!
System.out.println(concatenate(",", {"1"}));

마지막으로, 가변 인자는 재귀 호출에선 사용할 수 없어요. 어찌보면 오버로딩도니 두 메서드가 있는데, 이 둘이 구별할 수가 없다고 컴파일 에러를 띄워요. 그래서 가능하면 가변인자를 사용한 오버로딩은 지양해야 해요.

// 컴파일 에러!
public void concatenate(String... args){
	return concatenate(args);
}

좋은 웹페이지 즐겨찾기