그동안 메소드를 선언하고 사용할 때 매개변수 개수를 지정해주어야 했었습니다. 매개변수 개수를 다양하게 하고 싶다면 오버로딩
을 이용해서 처리했었고요.
JDK 1.5에서 추가된 가변인수
를 이용하면 매개변수를 동적으로 받을 수 있습니다.
가변인수
는 타입...
과 같이 작성하여 사용합니다.
public void method(타입... 가변인수명) {}
가변인수는 컴파일 과정에서 배열의 형태로 처리됩니다.
public void method(int... nums) {
//nums는 int[] nums로 취급
}
만약, 고정된 매개변수와 가변인수를 섞어서 사용한다면 반드시 가변 인수가 매개변수 리스트에서 가장 마지막에 위치해야합니다.
public void method(타입... 가변인수명, 타입 매개변수명) {} // X 불가능!!!
public void method(타입 매개변수명, 타입... 가변인수명) {} // O
다음은 가변인수를 사용한 메소드 예제입니다.
public class Main {
public static void main(String[] args) {
printNumbers(1);
printNumbers(1, 2);
printNumbers(1, 2, 3);
printNumbers(1, 2, 3, 4);
printNumbers(1, 2, 3, 4, 5);
}
public static void printNumbers(int... nums) {
for (int num : nums) { //int[]로 취급되어서 for each 사용 가능
System.out.println(num + " ");
}
System.out.println();
}
}
오버로딩을 이용했다면 함수를 다섯개 만들어야 했을텐데, 가변인수를 이용하니까 메소드를 하나만 작성하고도 오버로딩한 효과를 얻을 수 있었습니다.
한 클래스 내부에서 가변인수를 사용한 메소드는 오버로딩을 하지 않는 것이 권장됩니다. 그 이유는 컴파일 과정에서 컴파일러가 어떤 메소드를 사용해야하는지 구분하지 못하는 경우가 발생하기 때문입니다.
public class Main {
public static void main(String[] args) {
printNumbers(1, 2, 3);
}
public static void printNumbers(int num, int... nums) {
for (int n : nums) {
System.out.print(num + " ");
}
System.out.println();
}
public static void printNumbers(int... nums) {
for (int num : nums) {
System.out.println(num + " ");
}
System.out.println();
}
}
위 코드는 printNumbers를 오버로딩한 두 메소드인데요. 메소드를 호출하고 매개변수를 받는 과정에서 num과 nums를 구별하지 못합니다. 따라서 컴파일러는 두 메소드를 구분하지 못하겠다하고 에러를 발생시키게 됩니다.
이런 상황이 나올 수 있기 때문에 같은 클래스 내부에 가변인수를 사용한 메소드가 있다면 해당 메소드는 오버로딩을 하지 않아야합니다.
가변인수는 컴파일 과정에서 배열로 취급된다고 했습니다. 여기서 두 가지 문제가 발생하는데요.
첫 번째 문제는 배열 타입 매개변수 메소드와 가변인수를 혼용할 수 없는 문제입니다. 컴파일 과정에서 두 메소드 선언은 결국 똑같은 선언이 되어버리기 때문에 가변인수 메소드와 배열 타입 매개변수 메소드를 오버로딩해서 혼용할 수 없습니다.
두 번째 문제는 성능적인 문제입니다. 배열로 취급된다는 것은 컴파일과정에서 배열을 생성하고 그 내부에 전달된 인수들을 담아서 처리한다는 의미가 됩니다. 이는 메소드 실행마다 배열을 생성하고 초기화하는 과정이 포함되기 때문에 특정 상황에서는 성능적인 발목을 잡을 수 있게 됩니다.
그래서 가변인수가 편하다고 막 쓰기보다는 상황에 맞춰서(선언부가 너무 길어지는 4개 이상의 매개변수를 쓰는 상황 등) 가변인수와 오버로딩 중 적절한 것을 선택해서 사용하는 것을 권장드립니다.