ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 오버로딩 & 오버라이딩의 결정 시점 차이 (Overloading & Overriding)
    Java 2020. 2. 6. 13:18

    오버로딩(Overloading)오버라이딩(Overriding)은 객체지향의 특징 중 하나인 다형성을 지원하는 방법입니다.

     

    아시듯이, 

    오버로딩(Overloading)은 한 클래스 내에서 각각 다른 파라미터를 가진 동명의 메소드를 정의한 것이고,

    오버라이딩(Overriding)은 상속된 클래스에서 부모 클래스에 존재하는 메소드를 재정의한 것이지요.

     

    이 두 개념을 자바에서 구현할 때 차이점이 있습니다. 특히 오버로딩을 사용할 때 주의해서 사용해야 합니다.

    오버로딩과 오버라이딩된 동명의 메소드들 중에서 사용할 메소드를 결정하는 시점에 차이가 있습니다.

     


    1. 오버로딩(Overloading) & 오버라이딩(Overriding) 메소드 결정 시점 (JAVA)

    - 오버로딩된 메소드는 컴파일(Compile) 시에 어떤 메소드를 실행할지 결정됩니다.

    - 오버라이딩된 메소드는 런타임(Runtime) 시에 어떤 메소드를 실행할지 결정됩니다.

     


    2. Example

    바로 아래의 예제를 통해 확인해 보도록 하겠습니다.

    import java.util.ArrayList;
    import java.util.Arrays;
    import java.util.LinkedList;
    import java.util.List;
    import java.util.Vector;
    
    public class Overload {
    	public static void get(List<?> list) {
    		System.out.println("List");
    	}
    	
    	public static void get(ArrayList<?> list) {
    		System.out.println("ArrayList");
    	}
    	
    	public static void get(LinkedList<?> list) {
    		System.out.println("LinkedList");
    	}
    	
    	public static void main(String[] args) {
    		List<?>[] listArray = { new ArrayList<>(), new LinkedList<>(), new Vector<>() };
    		Arrays.stream(listArray).forEach(list -> get(list));
    	}
    }

    예제는 Overload 클래스 안에 get 메소드가 오버로딩되어 있습니다.

    main에서의 결과는 어떨까요? 

     

    - ArrayList로 초기화하여 get 메소드를 호출하면 "ArrayList"

    - LinkedList로 초기화하여 get 메소드를 호출하면 "LinkedList"

    - Vector로 초기화하여 get 메소드를 호출하면 "List"

    라고 추측하지만 이는 정답이 아닙니다. 모두 "List"의 결과를 화면에 반환합니다.

     

    그러면 오버라이딩된 메소드를 호출할 때는 어떨까요?

    import java.util.ArrayList;
    import java.util.Arrays;
    
    public class MyList<E> extends ArrayList<E> {
    	private static final long serialVersionUID = 1L;
    
    	/* (non-Javadoc)
    	 * @see java.util.ArrayList#get(int)
    	 */
    	@Override
    	public E get(int index) {
    		System.out.print("MyList get method returns = ");
    		return super.get(index);
    	}
    
    	@SuppressWarnings("unchecked")
    	public static void main(String[] args) {
    		ArrayList<String>[] listArray = new ArrayList[2];
    		listArray[0] = new ArrayList<String>();
    		listArray[1] = new MyList<String>();
    		Arrays.stream(listArray).forEach(list -> list.add("first object"));
    		Arrays.stream(listArray).forEach(list -> System.out.println(list.get(0)));
    	}
    }
    

    MyList 클래스를 만들어 ArrayList를 상속받아 get 메소드를 오버라이딩합니다.

    ArrayList<String> 배열의 0번에는 ArrayList 클래스를, 1번에는 MyList 클래스를 두었습니다.

    그리고 문자열을 추가한 뒤 get 메소드를 통해 출력하면 결과는 어떨까요?

     

    - ArrayList의 get 메소드의 결과를 출력하면 당연히 추가했던 문자열 "first object"

    - MyList의 get 메소드의 결과를 출력하면 재정의한대로 "MyList get method returns = first object"

    와 같은 결과를 볼 수 있습니다.

     


    3. Why ?

    이러한 결과가 나온 이유는 오버로딩과 오버라이딩 메소드의 결정 시점의 차이 때문입니다.

    컴파일 시점에서 List 클래스 배열인 listArray의 각 List 객체들이 어떤 List 클래스로 초기화될 지 알 수 없습니다.

    때문에 컴파일 시점에서 메소드가 결정되는 오버로딩의 경우, List 클래스의 파라미터를 갖는 메소드로 결정됩니다.

    반대로, 런타임 시점에서 new 연산자를 통해 실제 ArrayList, MyList 클래스의 객체로 생성되었음을 알 수 있습니다.

    때문에 런타임 시점에서 메소드가 결정되는 오버라이딩의 경우, 해당 클래스의 메소드가 실행될 수 있습니다.

     

     

    오버로딩의 이러한 동작 방식은 사용할 때 혼란을 줄 수 있습니다. 그렇기 때문에 상속된 클래스의 파라미터를 갖도록 오버로딩하는 것을 피하고, 같은 자료형의 조합 혹은 같은 수의 파라미터를 갖는 오버로딩 또한 사용하지 않는 것이 매끄러운 개발 진행에 도움이 될 것이라고 생각합니다.

     

     

    댓글

Designed by Tistory.