본문 바로가기

Java 문법 개념

오버로딩(Overloading) 과 오버라이딩(Overriding)

오버로딩(Overloading)

오버로딩이란, 간단히 말해서 " 메서드 다중 정의 " 이다.

 

같은 메서드 이름으로, 동일하거나 혹은 다른 동작을 하는 메서드들을 여럿 정의하는 것이다.


Java를 처음 배울 때 가장 먼저 접하는 println() 메서드 또한 오버로딩이 적용된 메서드이다.

 

우리가 println()의 매개변수에 문자열 타입, int 형 타입 등 여러 타입의 데이터를 넣어도

println() 메서드는 "출력"이라는 본인의 기능을 찰떡같이(?) 잘 수행한다.

 

메서드를 정의해보면 알겠지만, 메서드를 호출하여 매개변수에 넣을 수 있는 자료형의 타입은, 메서드를 정의할 때 매개변수에 지정해둔 특정 타입으로 알맞게 넣어야한다.

 

그런데 println() 메서드는 우리가 매개변수에 정수형, 문자열 등등... 여러 종류의 다양한 자료형의 데이터를 넣어도 어떻게 에러발생 없이 매번 잘 동작하는 것일까.

 

이는, println() 메서드를 선언&정의한 개발자가 오버로딩 개념을 적용하여 각각의 모든 자료형의 타입에 대하여 println() 메서드를 정의해 두었기 때문에 가능한 것이다.

 

println() 메서드가 실제로 정의된 코드를 보면 다음과 같다.

 

boolean, char, int 타입 외에도 다른 자료형에 대해서도 정의해 두었다.

 

생성자(Constructor) 도 대표적으로 오버로딩이 적용된 메서드의 한 예이다.    ( * 생성자도 일종의 메서드!! )

 

생성자의 이름은 문법상 클래스 이름으로 고정되고, 그 같은 이름의 메서드가 기본 생성자부터 시작해서 여러 갯수가 만들 어 질 수 있기 때문.

 


 

이처럼 오버로딩을 지원하는 Java에서는 오버로딩을 하기 위한 성립조건을 정해 두었다.

 

오버로딩 성립조건

  1. 오버로딩 하려는 메서드의 이름서로 동일해야한다.
  2. 오버로딩 하려는 메서드의 매개변수에서 매개변수의 타입 또는 갯수, 또는 순서가 서로 달라야한다.
  3. 오버로딩 하려는 메서드의 반환타입(return type)은 오버로딩 성립조건에 영향을 끼치지 않는다.

 

다음의 코드의 예시를 보면서 각각의 예시가 오버로딩 성립조건이 잘 적용됬는지 확인해 보자.

 

예시1

1
2
int add(int a, int b) {return a+b;}
int add(int x, int y) {return x+y;}
cs
  • 메서드의 이름은 서로 동일하기 때문에 문제가 없다.
  • 메서드의 매개변수의 타입이 서로 동일하고 갯수 또한 다르지 않으므로 오버로딩 조건이 잘 적용되지 않았다.
     * 매개변수의 이름은 영향을 미치지 않는다.

예시2

1
2
int add(int a, int b) {return a+b;}
int add(int a, int b) {return (long)(a+b);}
cs
  • 메서드의 이름은 서로 동일하기 때문에 문제가 없다.
  • 메서드의 매개변수의 타입이 서로 동일하고 갯수 또한 다르지 않으므로 오버로딩 조건이 잘 적용되지 않았다.
     * 메서드의 반환타입은 영향을 미치지 않는다.

예시3

1
2
int add(int a, long b) {return a+b;}
int add(long a, int b) {return a+b;}
cs
  • 메서드의 이름은 서로 동일하기 때문에 문제가 없다.
  • 메서드의 반환타입의 순서가 다르므로 오버로딩 조건이 잘 적용 되었다.
  • 즉 정상적으로 오버로딩 성립조건이 적용된 case 이다.

++추가++

예시 3의 case 에서, 만약에 메서드 호출을 add(3 , 3); 으로 호출하면 어떻게 될까?

 

에러가 발생한다.

 

왜냐하면 add(3, 3) 메서드 호출을 하게되면 저 위의 2개의 메서드 모두 사용가능(자동 형변환)하기 때문에, 컴파일러 입장에서는 둘 중에 어떤 메서드를 선택해서 사용해야할지 결정하지 못한다. (ambiguous 에러)

 

이럴 경우, int add( int a, int b ) { return a + b; } 라는 메서드를 추가로 생성(오버로딩 적용)해주면

컴파일러가 add(3, 3) 메서드를 정상적으로 호출할 수 있다.

 


 

오버라이딩(Overriding)

오버라이딩이란 조상으로 부터 상속받은 메서드를 자신(자손)에 맞게 변경하는 것이다.

 

Override(덮어쓰다) 라는 단어의 의미를 생각해보면 이해가 더 쉬울 것이다.  ( * Overloading 도 마찬가지... ^^)

 

오버로딩과 비슷하게 생겨서 둘의 개념을 혼동하지 않도록 주의해야한다.


오버라이딩 성립조건

  1. 메서드의 선언부가 조상메서드와 일치해야한다.  ( * 선언부 : 반환타입, 메서드이름, 매개변수 )
  2. 접근제어자의 범위가 조상메서드보다 좁아서는 안된다.
  3. 메서드에 선언된 예외의 갯수가 조상 메서드에 선언된 예외의 갯수보다 많아서는 안된다.
  4. 조상 메서드와 자손 메서드의 구현부가 같아도 이것도 오버라이딩이다.

 

++추가++

성립조건 3번에 대한 추가 설명.

 단순하게 선언된 예외의 갯수만 고려해서는 안되는 경우가 많다. 예외의 상속계층도 또한 함께 고려해야한다.

 Java에서 예외는 클래스로 존재하며 이 또한 상속계층도가 존재한다. 

 

예외의 상속계층도

 예를 들어서, 조상 메서드에 선언된 예외에 NullPointerException, ArithmeticException 이렇게 2개의 예외가 선언되어 있다고 가정해보자.

 그리고 이 조상 클래스를 상속받아서 위 2개의 예외가 선언된 조상의 메서드를 오버라이딩 하려고 한다.

 그래서 오버라이딩 성립조건 중, 3번을 충족시키기 위해서 자손의 메서드에 1개의 예외만 선언시켰다.

 (왜냐하면 조상 메서드에 선언된 예외의 갯수가 2개이고, 그렇다면 자손에 선언가능한 예외의 갯수는 0 ~ 2개 이므로.)

 

 그.런.데. 자손 메서드에 선언한 1개의 예외가 RuntimeException 이라면, 컴파일에러가 발생한다.

 

 비록 조상메서드에 선언된 예외의 "갯수"를 초과하지 말라는 규칙의 말 자체는 준수 했지만, 예외의 상속계층을 고려하지 않았기 때문이다.

 

NullPointerException, ArithmeticException 모두 RuntimeException 의 자손들이고, RuntimeException 에는 이 2개 이외에도 수많은 자손 예외를 가지고 있다.

 

자손 메서드에 RuntimeException 예외를 선언했다는 뜻은, RuntimeException 예외 아래에 있는 모든 자손 예외들을 전부 선언한 것과 같은 효과를 가진다.

 


++ O / X 퀴즈++

1. 조상 메서드를 오버라이딩 하면 그 오버라이딩 된 조상의 메서드는 상속을 받지 않는다.    → (X)

  • 조상메서드를 오버라이딩 했다고 그 메서드를 상속받지 않는 것은 아니다.

2. 조상 메서드를 오버라이딩 하면 그 오버라이딩 된 조상의 메서드는 오버라이딩 내용대로 수정된다    → (X)

  • 조상메서드의 원래 상태 그대로 온전히 상속을 받는다. 오버라이딩 한다고 내용이 수정되지 않는다.

3. 조상 메서드를 오버라이딩 하면, 조상메서드 말고 오버라이드된 자손메서드가 사용된다.     → (O)

 

 

 

22년 12월 28일 수요일 학습