JAVA/Java의 정석

Java의 객체지향 프로그래밍 [2] : 오버로딩(overloading)이란, 변수의 초기화

JWonK 2023. 6. 22. 16:34
728x90
반응형

▶ 오버로딩이란?


메서드도 변수와 마찬가지로 같은 클래스 내에서 서로 구별될 수 있어야 하기 때문에 각기 다른 이름을 가져야 한다. 그러나 자바에서는 클래스 내에 이미 사용하려는 이름과 같은 이름을 가진 메서드가 있더라도 매개변수의 개수 또는 타입이 다르면, 같은 이름을 사용해서 메서드를 정의할 수 있다.

 

이처럼, 한 클래스 내에 같은 이름의 메서드를 여러 개 정의하는 것을 '메서드 오버로딩(method overloading)' 또는 간단히 '오버로딩(overloading)'이라 한다.

 

 

 

 

 

 

▶ 오버로딩의 조건


같은 이름의 메서드를 정의한다고 해서 무조건 오버로딩인 것은 아니다. 오버로딩이 성립하기 위해서는 다음과 같은 조건을 만족해야한다.

 

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

 

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

 

 

 

 

 

 

 오버로딩의 장점


만일 메서드도 변수처럼 단지 이름만으로 구별된다면, 한 클래스 내의 모든 메서드들은 이름이 달라야한다. 그렇다면, 이전에 예로 들었던 10가지의 println메서드들은 각기 다른 이름을 가져야 한다.

 

예를 들면, 아래와 같은 방식으로 메서드 이름이 변경되어야 할 것이다.

void println()
void printlnBoolean(boolean x)
void printlnChar(char x)
void printlnString(String x)

하지만 오버로딩을 통해 여러 메서드들이 println이라는 하나의 이름으로 정의될 수 있다면, println이라는 이름만 기억하면 되므로 기억하기도 쉽고 이름도 짧게 할 수 있어 오류의 가능성을 많이 줄일 수 있다.

 

 

 

 

 

 

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


가변인자는 '타입... 변수명'과 같은 형식으로 선언하며, PrintStream클래스의 printf()가 대표적인 예이다.

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

 

위와 같이 가변인자 외에도 매개변수가 더 있다면, 가변인자를 매개변수 중에서 제일 마지막에 선언해야 한다.

 

 

※ 가변인자는 내부적으로 배열을 이용한다. 그래서 가변인자가 선언된 메서드를 호출할 때마다 배열이 새로 생성된다. 가변인자가 편리하지만, 이런 비효율이 숨어있으므로 꼭 필요한 경우에만 가변인자를 사용해야 한다.

 

 

class VarArgsEx{

    // No.1
    static String concatenate(String delim, String ... args){
        String result = "";
        
        for(String str : args){
        	result += str + delim;
        }
        
        return result;
    }
    
    // No,2
    static String concatenate(String ... args){
    	return concatenate("", args);
    }
    
}

위 두 메서드는 별 문제가 없어 보이지만 위의 예제를 컴파일하면 컴파일에러가 발생한다.

이유는 두 오버로딩된 메서드가 구분되지 않아서 발생하는 것이다. 가변인자를 선언한 메서드를 오버로딩하면, 메서드를 호출했을 때 이와 같이 구별되지 못하는 경우가 발생하기 쉽기 때문에 주의해야 한다.

 

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

 

 

 

 

 변수의 초기화


멤머변수 (클래스변수와 인스턴스변수)와 배열의 초기화는 선택적이지만, 자역변수의 초기화는 필수적이다.

 

[멤버 변수의 초기화 방법]

  1. 명시적 초기화 (explicit initialization)
  2. 생성자 (constructor)
  3. 초기화 블럭(initialization block)

- 인스턴스 초기화 블럭 : 인스턴스변수를 초기화 하는데 사용

- 클래스 초기화 블럭 : 클래스변수를 초기화 하는데 사용

 

 

 

 

⊙ 명시적 초기화(explicit initialization)

class Car{
    int door = 4;              // 기본형(primitive type) 변수의 초기화
    Engine e = new Engine();   // 참조형(reference type) 변수의 초기화
    
    // ...
}

 

 

 

 초기화 블럭(initialization block)

초기화 블럭에는 '클래스 초기화 블럭'과 '인스턴스 초기화 블럭' 두 가지 종류가 있다.

초기화 블럭 내에서는 메서드 내에서와 같이 조건문, 반복문, 예외처리구문 등을 자유롭게 사용할 수 있으므로, 초기화 작업이 복잡하여 명시적 초기화만으로는 부족한 경우 초기화 블럭을 사용한다.

 

class InitBlock{
    static { /* 클래스 초기화블럭입니다. */ }
    
    { /* 인스턴스 초기화블럭입니다. */ }
    
    // ...
}

 

→ 생성자보다 인스턴스 초기화 블럭이 먼저 수행된다

 

 

 

 

 

 멤버변수 초기화 시기와 순서


클래스변수의 초기화 시점 : 클래스가 처음 로딩될 때 단 한번 초기화된다.

인스턴스변수의 초기화시점 : 인스턴스가 생성될 때마다 각 인스턴스 별로 초기화가 이루어진다.

 

클래스변수의 초기화 순서 : 기본값 → 명시적초기화 → 클래스 초기화 블럭

인스턴스변수의 초기화 순서 : 기본값 → 명시적초기화 → 인스턴스 초기화 블럭 → 생성자

 

 

프로그램 실행 도중 클래스에 대한 정보가 요구될 때, 클래스는 메모리에 로딩된다. 예를 들면, 클래스 멤버를 사용했을 때, 인스턴스를 생성할 때 등에 이에 해당된다.

하지만, 해당 클래스가 이미 메모리에 로딩되어 있다면, 또다시 로딩하지 않는다. 물론 초기화도 다시 수행되지 않는다

728x90
반응형