[Java] 리턴타입은 메서드의 Overloading을 결정하는 조건이 아니다 (feat. Overriding과의 비교)

pintegral·2023년 1월 5일
0
post-thumbnail

메서드의 Overloading?

한 클래스 내에 사용하려는 이름과 동일한 메소드가 기존에 있더라도, 매개변수의 개수 또는 타입이 다르면 동일한 메서드명을 사용해서 정의할 수 있다. 이것이 바로 오버로딩이다.

그런데 이 때 메서드명, 매개변수 타입, 매개변수 개수까지 같으면서 리턴 타입만 다른 것은 오버로딩 할 수 없다.

아래의 코드를 통해서 예를 들어보자.

Code
class OverloadingTest {

	public static void main(String[] args) {
		OverloadingMethods om = new OverloadingMethods();

		om.print();
		System.out.println(om.print(3));
		om.print("Hello!");
		System.out.println(om.print(4, 5));
	}
}

class OverloadingMethods {
	public void print() {
		System.out.println("오버로딩1");
	}

	String print(Integer a) {
		System.out.println("오버로딩2");
		return a.toString();
	}

	void print(String a) {
		System.out.println("오버로딩3");
		System.out.println(a);
	}

	String print(Integer a, Integer b) {
		System.out.println("오버로딩4");
		return a.toString() + b.toString();
	}

}
Result
오버로딩1
오버로딩2
3
오버로딩3
Hello!
오버로딩4
45

위 코드는 아무런 문제없이 잘 실행되고 있다. print라는 같은 이름을 가진 네개의 메소드가 매개변수의 개수와 타입를 다르게 지정하여 지정하는 것이 가능하다는 것을 보여주고 있다.

단, 여기서 한번 더 강조할 점은 '리턴 값'만 다르게 지정하는 것은 오버로딩할 수 없다는 것.

또한 접근 제어자도 자유롭게 지정해 줄 수 있다. 각 메소드의 접근 제어자를 public, default, protected, private으로 다르게 지정해줘도 상관없다는 것이다. 접근 제어자만 다르게한다고 오버로딩이 가능하지 않다는 것도 알아두자.

결국 오버로딩은 매개변수의 차이로만 구현할 수 있다는 것이다. 매개변수가 다르다면 리턴 값은 다르게 지정할 수 있다는 것이 핵심이다.

When? Why?

그렇다면 오버로딩을 언제, 어떤 이유로 사용하면 적합할까
  1. 같은 기능을 하는 메서드를 하나의 이름으로 사용할 수 있다.

대표적인 예가 print 메서드이다. print 메서드는 int든 boolean이든 String이든 다양한 매개변수 타입을 지원한다.

이렇게 '출력하다.'라는 같은 기능을 가진 메소드들를 println이라는 하나의 이름으로 정의가 가능한 것이다.

  1. 메서드의 이름을 절약할 수 있다.

위에서 예로 들었던 print 메서드를 매개변수의 종류에 따라서 다르게 지정한다고 생각해보자. printInt, printDouble, printBoolean 등 수많은 메소드들의 이름을 정해줘야 할 것이다. 이는 프로그래머의 입장에서는 메서드네이밍 고민을 가중시킨다. 그리고 이런 이름들을 절약하여 다른 곳에 사용할 수 있는 가능성도 생긴다.

다형성을 구현하는 또 다른 기법 overriding..

다형성(하나의 메서드나 클래스가 다양한 방법으로 동작하는 것)의 대표적인 예시로는 오버로딩과 오버라이딩이 있다.
둘 다 다형성을 구현한다는 공통점을 가지고 있지만, 오버라이딩은 부모클래스로부터 상속받은 자식 클래스가 재정의(override)하는 행위이기 때문에,

1) 메서드명, 매개변수, 리턴값이 모두 같아야 한다.

2) 자식 클래스에서 오버라이딩하는 메서드의 접근 제어자는 부모 클래스보다 더 좁게 설정할 수 없다.

또한

3) 오버로딩은 컴파일 중에 발생하는 '정적' 다형성이고, 오버라이딩은 런타임 중에 발생하는 '동적' 다형성이다.
(단, @Override 어노테이션을 통해 컴파일 시 오버라이딩이 실제 시행 여부는 검증할 수 있다.)

어노테이션? 컴파일러에게 특정한 정보를 제공해주는 역할

아래 코드를 살펴보자

Code
public class OverridingTest {

	public static void main(String[] args) {
		Person person = new Person();
		Child child = new Child();
		Senior senior = new Senior();
		
		person.laugh();
		child.laugh();
		senior.laugh();
	}
}

class Person {
	void laugh() {
		System.out.println("ㅎㅎ");
	}
}

class Child extends Person {
	@Override // 컴파일 중에 검증
	protected void laugh() {
		System.out.println("ㅋㅋ");
	}
}

class Senior extends Person {
	@Override
	public void laugh() {
		System.out.println("^^");
	}
}
Result
ㅎㅎ
ㅋㅋ
^^

Overriding과 비교하며 Overloading 정리

기준OverridingOverloading
접근 제어자부모 클래스의 메소드의 접근 제어자보다 더 넓은 범위의 접근 제어자를 자식 클래스의 메소드에서 설정할 수 있다.모든 접근 제어자를 사용할 수 있다.(즉 달라도 상관없다)
리턴타입동일해해야 한다.달라도 된다.(같아도 호출 시 에러 X)
메서드명동일해야 한다.동일해야 한다.
매개변수동일해야 한다.달라야만 한다.
다형성 실현 시점런타임(단, 어노테이션을 통해 컴파일 타임에도 검증 가능)컴파일 타임

위의 내용을 바탕으로 둘을 비교 정리해보면 이렇다. 각 기법이 어떤 상황에서 어떻게 사용되고, 왜 사용되는지 알아두면 더 나은 프로그램을 설계할 수 있을 것이다.

Reference
profile
문제를 끝까지 해결하려는 집념의 개발자

0개의 댓글