[기본 개념] 1 | (3.1) 오버로딩

728x90

[기본 개념] 1 | (3.1) 오버로딩

1> 오버로딩이란?

2> 오버로딩의 조건

3> 오버로딩의 예

4> 오버로딩의 장점

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

1. 오버로딩이란?

 메서드도 변수와 마찬가지로 각기 다른 이름을 가져야 하는데 자바에서는 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메서드를 정의할 수 있다. 이처럼 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 '오버로딩(overloading)'이라고 한다.

2. 오버로딩의 조건

오버로딩이 성립하기 위한 조건은 다음과 같다.

 

1. 메서드의 이름이 같아야 한다.

2. 매개변수의 개수 또는 타입이 달라야 한다.

 

 매개변수가 다르면 서로 구별될 수 있기에 오버로딩이 가능하며 위 조건을 만족시키지 못하는 메서드는 중복 정의로 에러가 발생한다. 그리고 오버로딩된 메서드들은 매개변수에 의해서만 구별될 수 있으므로 반환 타입은 오버로딩을 구현하는데 아무런 영향을 주지 못한다.

3. 오버로딩의 예

 가장 대표적인 것은 println메서드이다. 실제로는 println메서드를 호출할 때 매개변수로 지정하는 값의 타입에 따라서 호출되는 println메서드가 달라진다. PrintStream클래스에는 어떤 종류의 매개변수를 지정해도 출력할 수 있도록 10개의 오버로딩된 println메서드를 정의해놓고 있다.

 

        void println( )

        void println(boolean x)

        void println(char x)

        void println(char[ ] x)

        void println(double x)

        void println(float x)

        void println(int x)

        void println(long x)

        void println(Object x)

        void println(String x)

 

 println메서드를 호출할 때 매개변수로 넘겨주는 값의 타입에 따라 위의 오버로딩된 메서드들 중 하나가 선택되어 실행되는 것이다.

 

<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형 매개변수가 하나씩 선언되어 있지만 서로 순서가 달라 구분될 수 있으므로 오버로딩이 성립한다.

 

같은 일을 하지만 매개변수를 달리해야 하는 경우에,

이와 같이 이름은 같고 매개변수를 다르게 하여 오버로딩을 구현한다.

4. 오버로딩의 장점

메서드도 변수처럼 이름으로 구별됐다면, 아래와 같은 방식으로 메서드 이름이 변경되어야 할 것이다.

 

        void println( )

        void printlnBoolean(boolean x)

        void printlnChar(char x)

        void printlnDouble(double x)

        void printlnString(String x)

 

 이렇게 되면, 같은 기능을 하는 메서드들이지만 서로 다른 이름을 가져야 되기 때문에 이름 짓기도 어렵고 일일이 구분해서 기억하기도 부담된다. 하지만 오버로딩을 통해 여러 메서드들이 println이라는 하나의 이름으로 정의될 수 있으면, println이라는 이름만으로도 오류의 가능성도 줄일수 있고 기억하기도 쉽다.

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

 매개변수의 개수를 동적으로 지정해 줄 수 있는 기능을 '가변인자(variable arguments)'라고 한다. 가변인자는 '타입... 변수명'과 같은 형식으로 선언하며, printf( )가 대표적인 예이다.

 

        public PrintStream printf(String format, Object... args) { . . . }

 

 위와 같이 가변인자 외에도 매개변수가 더 있으면, 가변인자를 제일 마지막에 선언해야 한다. 그렇지 않으면, 컴파일 에러가 발생한다. 가변인자인지 아닌지를 구별할 방법이 없기 때문이다.

 

 만일 여러 문자열을 하나로 결합하여 반환하는 concatenate메서드를 작성한다면, 매개변수의 개수를 다르게 해서 여러 개의 메서드를 작성해야 할 것이다.

 

        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"})) ;    // 배열도 가능

 

 이처럼 가변인자는 내부적으로 배열을 이용한다. 가변인자가 편리하지만, 이런 비효율적인 면도 있다는 것을 알아야 한다. 

 

 매개변수의 타입을 배열로 하면, 반드시 인자를 지정해줘야 하기 때문에, 인자를 생략할 수 없고 null이나 길이가 0인 배열을 인자로 지정해줘야 한다는 차이점이 있다.

 

가변인자를 오버로딩할 때 주의해야 할 점을 예제로 알아보자.

 

예제/VarArgsEx.java

class VarArgsEx {
    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);
    }
 */
}   // class
실행결과 

100200300
100-200-300-
1,2,3,
[ ]
[ ]

 

 concatenate메서드는 매개변수로 입력된 문자열에 구분자를 사이에 포함시켜 결합해서 반환한다. 가변인자로 매개변수를 선언했기 때문에 문자열을 개수의 제약 없이 매개변수로 지정할 수 있다.

 

concatenate메서드와 주석처리 된 concatenate메서드에서 주석을 푼다면, 가변인자를 선언한 메서드를 오버로딩하여 오버로딩된 메서드가 구분되지 않아 컴파일에러가 발생한다. 

 

따라서 가변인자를 사용한 메서드는 오버로딩하지 않는 것이 좋다.

 

 

 

 

출처 | Java의 정석 (남궁 성)

728x90