본문 바로가기
🌐 Language/java

[ Java ] 오버로딩(Overloading) & 오버라이딩(Overriding)

by 깸뽀 2023. 1. 3.
728x90

📌 오버로딩(Overloading) / 확장

- 오버로딩은 자바의 한 클래스 내에 같은 이름의 메서드를 여러개 가지면서 매개변수의 타입과 개수를 다르게 하여 다양한 유형의 호출에 응답할 수 있도록 하는 방식 ( 인자를 기준으로 판단! )

- 오버로딩은 메서드 오버로딩과 생성자 오버로딩이 있으며 실제 적용되는 것은 같다

 

 

🔸 오버로딩의 조건

  1. 메소드의 이름이 같아야 한다.
  2. 매개변수의 개수 또는 타입이 달라야 한다.
  3. 접근제어자도 자유롭게 지정해 줄 수 있다. (public, default, protected, private)
  4. return값 다르다고 해서, 접근제어자만 다르다고 해서, 매개 변수 이름이 다르다고 해서 오버로딩이라 하지 않는다.

오버로딩은 매개변수의 차이로만 구현할 수 있다.

리턴 값만, 접근제어자만, 매개 변수 이름만 다르게 지정한다고 해서 오버로딩이 가능하지 않다.

 

 

💻 메소드 오버로딩

public class Calculator {

    // 정사각형의 넓이
    double areaRectangle(double width) {
        return width * width;
    }

    // 직사각형의 넓이
    double areaRectangle(double width, double height) {
        return width * height;
    }

    public static void main(String[] args) {
        Calculator myCalcu = new Calculator();

        // 정사각형의 넓이 구하기
        double result1 = myCalcu.areaRectangle(10);
        // 직사각형의 넓이 구하기
        double result2 = myCalcu.areaRectangle(10, 20);

        System.out.println("정사각형 넓이 = " + result1);
        System.out.println("직사각형 넓이 = " + result2);
    }
}

// 결과
// 정사각형 넓이 = 100.0
// 직사각형 넓이 = 200.0

 

 

💻 생성자 오버로딩

public class Car {

    // 필드
    String company = "현대자동차";
    String model;
    String color;
    int maxSpeed;

    // 생성자 1
    public Car() {

    }
    // 생성자 2
    public Car(String model) {
        this.model = model;
    }
    // 생성자 3
    public Car(String model, String color) {
        this.model = model;
        this.color = color;
    }
    // 생성자 4
    public Car(String model, String color, int maxSpeed) {
        this.model = model;
        this.color = color;
        this.maxSpeed = maxSpeed;
    }

    // 객체 생성 시 생성자 선택
    public static void main(String[] args) {
        Car car1 = new Car();
        System.out.println("car1.company : " + car1.company );
        System.out.println("----------------------------------" );

        Car car2 = new Car("자가용");
        System.out.println("car2.company : " + car2.company );
        System.out.println("car2.model : " + car2.model );
        System.out.println("----------------------------------" );

        Car car3 = new Car("자가용", "빨강");
        System.out.println("car3.company : " + car3.company );
        System.out.println("car3.model : " + car3.model );
        System.out.println("car3.color : " + car3.color );
        System.out.println("----------------------------------" );

        Car car4 = new Car("자가용", "빨강", 200);
        System.out.println("car4.company : " + car4.company );
        System.out.println("car4.model : " + car4.model );
        System.out.println("car4.color : " + car4.color );
        System.out.println("car4.maxSpeed : " + car4.maxSpeed );
        System.out.println("----------------------------------" );
    }
}

// 결과
/*
car1.company : 현대자동차
----------------------------------
car2.company : 현대자동차
car2.model : 자가용
----------------------------------
car3.company : 현대자동차
car3.model : 자가용
car3.color : 빨강
----------------------------------
car4.company : 현대자동차
car4.model : 자가용
car4.color : 빨강
car4.maxSpeed : 200
----------------------------------
*/

 

 

💡 오버로딩의 장점

  • 다형성을 구현할 수 있다.
    • 같은 기능이지만 입력값을 달리하고 싶을 때 매개변수의 타입에 맞춰서 다른 이름을 갖는 메소드를 생성해야하지만, 오버로딩을 사용하면 같은 이름을 가진 메소드의 매개변수 타입만 바꿔서 이용해도 쉽게 처리 할 수 있다.
  • 소스 코드의 가독성이 좋아진다.
    • 유사한 기능을 의미하는 동일한 이름의 메소드들이 묶여져 있기 때문에 개발자나 다른 사람이 소스코드 파악이 빠르고 이해가 쉽다.
  • 메소드의 이름을 절약할 수 있다.
    • 메소드 생성 시, 근본적으로 동일한 기능을 수행하지만 서로 다른 이름을 가져야하기 때문에
    • 각각의 이름을 달리 설정해줘야하는 번거로움이 생긴다.
    • 하지만 오버로딩을 이용해 유사한 기능들은 동일한 이름을 갖는 메소드를 정의할 수 있기 때문에 다른 기능을 가진 많은 메소드들을 정의하더라도 이름을 짓는데 무리가 없다.
  • 기능 예측이 쉬워진다.
    • 오버로딩을 사용하는 경우 중 하나는 같은 기능을 하지만 입출력값의 타입을 변형하기 위함이다.
    • 메소드의 이름을 동일하게 지정해두기 때문에 개발자가 필요한 기능을 찾을 경우 메소드 이름으로 유사한 기능들을 쉽고 빠르게 예측할 수 있다.

 

 

📌 오버라이딩(Overriding) / 재정의

- 오버라이딩은 상속 관계에 있는 부모 클래스에서 이미 정의된 메소드를 자식 클래스에서 같은 시그니처를 갖는 메소드로 다시 정의하는 것

- 즉, 상위 클래스로부터 상속받은 메서드의 동작만을 재정의 하는 것이다.

 

자바에서 자식 클래스는 부모 클래스의 private 멤버를 제외한 모든 메소드를 상속받는다.

이렇게 상속받은 메소드는 그대로 사용해도 되고, 필요한 동작을 위해 재정의하여 사용할 수도 있다.

메소드 오버라이딩이란 상속받은 부모 클래스의 메소드를 재정의하여 사용하는 것을 의미한다.

 

 

🔸 오버라이딩의 조건 

  1. 오버라이드 하고자 하는 메소드가 상위(부모) 클래스에 존재해야 한다.
  2. 상위(부모) 메소드와 메소드 이름이 같아야 한다.
  3. 상위(부모) 메소드와 메소드 파라미터 개수와 자료형이 같아야 한다.
  4. 상위(부모) 메소드와 메소드 리턴형이 같아야 한다.
  5. 상위(부모) 메소드와 동일하거나 내용이 추가되어야 한다.
  6. 상위(부모) 클래스의 메소드보다 더 큰 범위의 예외를 선언할 수 없다.
  7. 상위(부모) 클래스의 메소드보다 접근 제어자를 더 좁은 범위로 변경할 수 없다.
    (final이 지정된 메서드, private 접근 제어자를 가진 메서드는 상속 자체가 불가능)

 

class Parent {

    void display() { System.out.println("부모 클래스의 display() 메소드입니다."); }

}

class Child extends Parent {

    void display() { System.out.println("자식 클래스의 display() 메소드입니다."); }

}

 

public class Inheritance05 {

    public static void main(String[] args) {

        Parent pa = new Parent();

        pa.display();

        Child ch = new Child();

        ch.display();

        Parent pc = new Child();

        pc.display(); // Child cp = new Parent();

    }

}

// 결과
/*
부모 클래스의 display() 메소드입니다.
자식 클래스의 display() 메소드입니다.
자식 클래스의 display() 메소드입니다.
*/

 

 

💡 오버라이딩을 사용하는 이유

  • 자식 클래스가 부모 클래스의 메소드를 상속받아도 다른 기능을 수행하고자 하는 경우가 생긴다.
    1. 가장 흔한 경우가 바로 Object Class의 toString 기능이다.
      모든 참조 클래스는 Object 클래스를 기본적으로 상속받기 때문에 toString() 메소드가 존재하는데
      새롭게 선언한 클래스가 Object클래스의 toString과는 다른 String 값을 출력하도록 설정해야 하는 경우가 종종 존재한다. 이런 경우 메소드 오버라이딩을 사용한다.
    2. Person이라는 클래스는를 상속받고 있는 Student 클래스는 Person 클래스의 내의 hello() 메서드와 다른 결과값을 얻기 위해 오버라이딩 해서 사용하는 경우가 있을 수 있다.
      물론 Student 클래스에 helloStudent() 라는 식으로 메서드를 새로 만들어 사용하는 것도 컴파일상에 문제는 전혀 되지 않지만 OOP 적 관점에서는 바람직 하지 않을 수 있다. 코드의 재사용성 능력이 떨어지기 때문이다.

 

+)

@Override 어노테이션은 없어도 오버라이딩이 적용되어 정상적으로 동작한다.
그렇다면 @Override 어노테이션을 쓰는 이유는 무엇일까?

@Override 어노테이션은 시스템에서 오버라이딩한 메서드라고 알리는 역할로 오버라이딩이 잘못된 경우 경고를 준다.

예를 들어

백엔드 단에서 사용되는 라이브러리 중 하나가 업데이트되어 상속하는 클래스 메서드의 시그니처가 바뀌었다고 가정하면,

@Override 어노테이션이 적용되지 않은 상태에서는 전에 오버라이드 한 메서드가 업데이트 이후 그냥 추가적인 메서드로 인식되어 컴파일 오류가 발생하지 않습니다. 이때 @Override 어노테이션을 적용함으로써 의도적으로 컴파일 오류를 일으켜 작동방식이 바뀌는 것을 대비할 수 있다.

또한 @Override를 표시함으로써 코드 리딩 시에 해당 메서드가 오버라이딩하였다는 것을 쉽게 파악할 수 있다는 장점이 있다.

 

Overloading vs Overriding 정리

Overloading

오버로딩은 한 클래스 내에 여러 개의 같은 이름의 메소드를 정의하는 것을 말한다. 이렇게 메소드의 이름을 동일하게 만들어 프로그램의 가독성을 증가시키고, 메소드의 이름을 절약할 수 있다.

  • 범위 : 같은 클래스 내에서 적용되는 개념
  • 메소드 이름 : 원 메소드와 동일해야 한다
  • 매개변수 : 원 메소드와 항상 달라야 한다
  • 리턴 타입 : 원 메소드와 상관 없음 ( 달라질 수 있다 )
  • 접근 제어자 : 원 메소드와 상관 없음 ( 달라질 수 있다 )

Overriding

오버라이딩은 상위 클래스로부터 상속받은 메서드의 동작만을 재정의 하는 것으로, 자식 클래스가 부모 클래스의 메소드를 상속받아도 다른 기능을 수행하고자 하는 경우 메소드를 입맛에 맞게 변경하여 코드의 재사용성을 높일 수 있다.

  • 범위 : 클래스 상속관계에서 적용되는 개념
  • 메소드 이름 : 원 메소드와 동일해야 한다
  • 매개변수 : 원 메소드와 동일해야 한다
  • 리턴 타입 : 원 메소드와 동일해야 한다
  • 접근 제어자 : 원 메소드보다 넓거나 같은 범위를 가져야 한다

둘 다 객체지향 언어의 특징인 다형성 중 하나이다.

728x90

댓글