본문 바로가기

Java/Chapter 11. 메소드 오버로딩과 String 클래스

[Java] 11.01 - 메소드 오버로딩(Method Overloading)

들어가며

 한 클래스 내에 동일한
이름의 메소드를

 둘 이상 정의하는 것은
허용되지 않는다.

 그러나 매개변수의 선언이
다르면 가능하다.

 그리고 이것을 메소드
오버로딩이라 한다.

 

메소드 오버로딩의 조건

 호출할 메소드를 찾을 때,

 다음 두 가지 정보를 참조하여
메소드를 찾게 된다.

  • 메소드의 이름
  • 메소드의 매개변수 정보

 예를 들어서 다음 메소드의
호출문을 보자.

MyHome home = new MyHome();
home.mySimpleRoom(3, 5);

 위의 문장에서 호출하는
메소드를 찿을 때

 다음 두 가지 정보가 사용된다.

  • 메소드의 이름이 mySimpleRoom이다.
  • 3과 5를 인자로 전달받을 수 있는 메소드이다.

 즉 위의 메소드 호출문이
찾는 메소드의 모양새는
다음과 같다.

반환형은 임의로 void로 선언하였다. 즉, 반환형은 다를 수 있다.
void mySimpleRoom(int n1, int n2,){ . . . }

 따라서 MyHome 클래스
내에 다음과 같이

 myHomeRoom 메소드가
둘 이상 존재해도 문제가
되지 않는다.

 매개변수의 선언이 다르면
호출된 메소드의 구분이
가능하기 때문이다.

class MyHome{
    void mySimpleRoom(int n){ . . . }
    void mySimpleRoom(int n1, int n2){ . . . }
    void mySimpleRoom(double d1, double d2){ . . . }
}

 정리하면, 메소드의 이름이
같더라도 매개변수 선언이
다르면

 메소드 호출문의 전달인자를
통해서 호출된 메소드를 구분할
수 있다.

 때문에 매개변수의 선언이
다르면

 동일한 이름의 메소드 정의를
허용하는데,

 이를 가리켜 '메소드의 오버로딩'
이라 한다.


 메소드 오버로딩이 성립하려면
매개변수 선언이 달라야 한다고
했는데,

 구체적으로 매개변수의 수
또는 형(type)이 달라야 한다.

 즉, 다음의 경우에는 메소드
오버로딩이 성립한다.

 매개변수의 수가 다르기 때문이다.

void simpleMethod(int n){ . . . }
void simpleMethod(int n1, int n2){ . . . }

 다음의 경우도 메소드 오버로딩이
성립한다.

 매개변수의 형이 다르기 때문이다.

void simpleMethod(int n){ . . . }
void simpleMethod(double d){ . . . }

 그러나 다음과 같이 반환형이
다른 경우에는

 메소드 오버로딩이 성립하지
않는다.

int simpleMethod(){ . . . }
double simpleMethod(){ . . . }

 반환형은 호출할 메소드를
선택하는데 있어서의 판단
기준이 아니기 때문이다.

 

얘야, 인생이란 원래 자기 생각대로 되지 않는 법이란다.

 다음과 같이 오버로딩 된
메소드가 존재한다고
가정해보자.

 이 경우 매개변수의 수는
같지만

 매개변수의 형이 다르기
때문에 메소드 오버로딩이
성립한다.

class AAA{
    void simple(int p1, int p2){ . . . }
    void simple(double p1, double p2){ . . . }
}

 그렇다면 이 상황에서 다음과
같이 인스턴스를 생성하고

 메소드를 호출하면 어떤
메소드가 호출되겠는가?

AAA inst = new AAA();
inst.simple(7, 'K');	// 어떤 메소드가 호출될 것인가

 위의 메소드 호출은 애매하다.

 이유는 메소드의 인자 전달
과정에서 발생하는 형 변환
때문이다.

 사실 AAA 클래스에는 정수
10과 문자 'K'를 인자로 전달받는

 simple 메소드가 정의되어
있지 않다.

 때문에 장동 형 변환 규칙을
적용하여 호출할 메소드를
찾게 된다.

 그런데 문제는 클래스에
정의된 두 simple 메소드
모두

 형 변환 규칙을 적용했을 때
호출이 가능하다는데 있다.

 그래서 위의 메소드 호출문을
애매하다고 한 것이다.


 결론을 말하자면 이러한
상황에서는

 이전에 설명한 자동 형 변환
규칙을 적용하되

 가장 가까운 위치에 놓여있는
자료형으로의 형 변환을 우선
시도한다.

 때문에 위의 메소드 호출문에
의해 호출되는 메소드는 다음과
같다.

void simple(int p1, int p2){ . . . }

 오버로딩 된 메소드를 호출할
때에는

 전달인자의 자료형과 매개변수의
자료형을 일치시키는 것이 좋다.

 그래서 애매한 상황을 지양하는
것이 좋다.

 

생성자도 오버로딩의 대상이 될 수 있다.

 생성자도 매개변수의 선언이
다르면, 둘 이상 정의가 가능하다.

 즉, 생성자도 오버로딩 할 수 있다.

 이와 관련하여 다음 예제를
보자.

class Person{
    private int regiNum;    // 주민등록 번호
    private int passNum;    // 여권 번호

    Person(int rnum, int pnum){
        regiNum = rnum;
        passNum = pnum;
    }

    Person(int rnum){
        regiNum = rnum;
        passNum = 0;
    }

    void showPeronalInfo(){
        System.out.println("주민등록 번호: " + regiNum);

        if(passNum != 0)
            System.out.println("여권 번호: " + passNum + '\n');
        else
            System.out.println("여권을 가지고 있지 않습니다." + '\n');
    }
}

class ConOverloading{
    public static void main(String[] args){
        // 여권 있는 사람의 정보를 담은 인스턴스 생성
        Person user1 = new Person(335577, 112233);

        // 여권 없는 사람의 정보를 담은 인스턴스 생성
        Person user2 = new Person(775544);

        user1.showPeronalInfo();
        user2.showPeronalInfo();
    }
}
/*
실행 결과
주민등록 번호: 335577
여권 번호: 112233

주민등록 번호: 775544
여권을 가지고 있지 않습니다.
*/

 위의 Person 클래스에 정의된
두 생성자는 다음과 같다.

 생성자의 매개변수 선언이
다르므로,

 이 둘은 오버로딩 관계에 있다.

// 여권이 있는 사람을 위한 생성자
Person(int rnum, int pnum){
    regiNum = rnum;
    passNum = pnum;
}

// 여권이 없는 사람을 위한 생성자
Person(int rnum){
    regiNum = rnum;
    passNum = 0;
}

 이로 인해 다음과 같이
두 가지 방법으로 인스턴스
생성이 가능하다.

Person user1 = new Person(335577, 112233);
// 생성자  Person(int rnum, int pnum){ . . . } 호출
Person user2 = new Person(775544);
// 생성자  Person(int rnum){ . . . } 호출

 이러한 생성자의 오버로딩은
다양한 상황을 고려한 인스턴스
생성을 가능하게 한다.

 예제에서 보였듯이 여권이
있는 사람의 정보를 담은
인스턴스뿐 아니라

 여권이 없는 사람의 정보를
담은 인스턴스 생성도 가능하게
한다.

 

키워드 this를 이용한 다른 생성자의 호출

 앞서 예제에서 정의한 다음
Person 클래스를 다시 관찰하자.

 특히 생성자를 관찰하자.

class Person{
    private int regiNum;    // 주민등록 번호
    private int passNum;    // 여권 번호

    Person(int rnum, int pnum){
        regiNum = rnum;
        passNum = pnum;
    }

    Person(int rnum){
        regiNum = rnum;
        passNum = 0;
    }

    void showPeronalInfo(){ . . . }
}

 이 중에서 두 번째로 위치한
생성자를 대신해서

 다음과 같이 생성자를 정의할
수도 있다.

앞서 제시한 예제에서 두 번째 생성자를 다음 생성자로 대체한 후 컴파일 및 실행해보자.
Person(int rnum){
    this(rnum, 0);    // rnum과 0을 인자로 받는 다른 생성자를 호출
}

 위에서 사용된 this는 '오버로딩
된 다른 생성자'를 의미한다.

 즉 위의 문장은 rnum과 0을
인자로 받는 다른 생성자의
호출을 의미한다.

 결국 위와 같이 생성자를
정의하면,

 이 생성자는 초기화할 값을
전달받는 역할만 하고,

 실제 초기화는 첫 번째로
정의된 생성자를 통해서
진행하는 형태가 된다.

 이와 같이 this를 이용한
생성자의 정의를 통해

 중복된 코드의 수를 줄이는
효과를 얻을 수 있다.

 

키워드 this를 이용한 인스턴스 변수의 접근

 앞서 키워드 this를 이용한
생성자의 호출에 대해 설명을
했는데,

 this는 다른 의미로도 사용이
된다.

 이와 관련하여 다음 예제를 보자.

 그리고 이 예제에서 보이는
this는 어떤 의미를 갖는지
판단해보자.

class SimpleBox{
    private int data;

    SimpleBox(int data){
        this.data = data;
    }

    void setData(int data){
        this.data = data;
    }

    int getData(){
        return this.data;
    }
}

class ThisInst{
    public static void main(String[] args){
        SimpleBox box = new SimpleBox(99);
        System.out.println(box.getData());

        box.setData(77);
        System.out.println(box.getData());
    }
}
/*
실행 결과
99
77
*/

 클래스 SimpleBox 내에는
인스턴스 변수로 data가
선언되었다.

 따라서 인스턴스 메소드
내에서,

 그리고 생성자 내에서 data
라는 이름의 변수에 접근하면,

 이는 인스턴스 변수 data의
접근으로 이어진다.

여기까지는 이미 알고 있는 내용이다.

 그러나 매개변수로 data라는
이름의 변수가 선언되면

 상황은 달라진다.

class SimpleBox{
    private int data;

    SimpleBox(int data){
        this.data = data
        // 여기서의 data는 매개변수 data를 의미함
    }
}

 위와 같이 매개변수의 이름이
인스턴스 변수의 이름과 동일하게
선언된 경우,

 선언된 지역 내에서의 해당
이름은 매개변수를 의미하게
된다.

 하지만 키워드 this를 이용하면
이 영역 안에서도 인스턴스 변수에
접근을 할 수 있다

class SimpleBox{
    private int data;

    SimpleBox(int data){
        this.data = data
        // 여기서의 this.data는 인스턴스 변수 data를 의미함
    }
}

 즉 this.data에서 this가 의미하는
것은 '이 문장이 속한 인스턴스'이다.

 따라서 this.data는 인스턴스 변수
data를 의미라는 것이 된다.

 따라서 앞서 예제에서 보였듯이,

 다음과 같은 생성자의 정의가
가능하다.

class SimpleBox{
    private int data;

    SimpleBox(int data){
        this.data = data
        // 매개변수 data의 값을 인스턴스 변수 data에 저장
    }
}

참고 및 출처

윤성우의 열혈 Java 프로그래밍
국내도서
저자 : 윤성우
출판 : 오렌지미디어 2017.07.05
상세보기