[Java]class: 오버라이딩(overriding)과 오버로딩(overloading)

god1hyuk·2022년 7월 21일
3

Java

목록 보기
1/3
post-thumbnail

나의 첫 기술 블로그.

TIL이나 알고리즘 문제 풀이 정도 업로드 하였지만 공부하면서 기록하는게 리마인드도 되고 좋을 것 같다는 생각이 들어 오늘부터 시작한다.

전문적인 기술 블로그가 아닌 개인적으로 공부하며 깨달은 나의 관점에서의 정의이기 때문에 그 점 참고하길 바란다.

첫번째 주제는 자바의 꽃이라 불리는 클래스(class) 문법의 정말 주요 개념, 오버라이딩(overriding)과 오버로딩(overloading)에 대해 살펴본다.

이 둘의 공통점은 클래스의 인스턴스 멤버인 메소드를 재정의 또는 확장의 개념이다. 아주 간단히 차이점을 꼽자면 오버라이딩(overriding)은 부모 클래스의 상속을 받은 자식 클래스에서 확장하는 개념, 오버로딩(overloading)은 하나의 클래스 내부에서 확장하는 개념이다. 본격적으로 이 두가지 개념에 대해 파헤쳐보자.

1. 오버라이딩(overriding)

상속 받은 자식 클래스는 부모 클래스가 물려준 메소드를 곧이 곧대로 따라야만 하는가?

자식 클래스에서 물려 받은 메소드를 조금 변형해서 사용하고 싶다면, 이 오버라이딩을 사용하여 자유롭게 기능을 추가 또는 재정의를 해서 사용할 수 있다.

단, 이 조건은 충족해야 한다.

  • 메소드의 이름이 일치해야 함
  • 메소드 매개변수의 개수, 순서 그리고 데이터 타입 일치해야 함
  • 메소드의 return 타입이 일치해야 함

위 조건을 충족하지 않으면 오버라이딩이 성립될 수 없다.

예제를 한번 살펴보자.

  • 예제 시나리오
    자동차(Car)라는 큰 카테고리의 부모 클래스에서 기본적으로 속도(speed)에 관한 정보를 가지고 있고 속도를 조절 하는 메소드(setSpeed())가 있다. 부모 클래스에서는 단순히 변경할 속도를 입력 받으면 현재 속도(speed)에 더해주어 현재 속도를 변경하여 return 하는 로직을 가지고 있다. 자식 클래스 소나타(Sonata) 클래스는 Car 클래스를 상속 받아 기본 정보인 속도(speed)를 갖게 된다. 거기에 추가로 Sonata 클래스는 최고 속도(MAX_SPEED)라는 정보를 가지고 있다. 그런데 Sonata 클래스에서는 속도를 조절하는 메소드(setSpeed()) 기능에서 조금 다른 로직을 가지고 싶다. 기본적으로 속도를 변경하지만 속도가 Sonata에서만 가지고 있는 최고 속도를 넘게 되면 속도를 제한한 최고 속도로 맞춰주고 싶다.
class Car {
    int speed = 0;

    public void setSpeed(int speed_change) {
        this.speed += speed_change;
        System.out.println(this.speed);
    }
}

class Sonata extends Car {
    final int MAX_SPEED = 150;

    public int setSpeed(int speed) {
        this.speed += speed;

        if (this.speed > MAX_SPEED) {
            this.speed = MAX_SPEED;
        }

        return this.speed;
    }
}

public class CarOverridingTest {
    public static void main(String[] args) {
        Car car = new Car();
		car.setSpeed(30);

        Sonata sonata = new Sonata();
		sonata.setSpeed(180);
    }
}

위 코드를 실행하면

java: setSpeed(int) in Sonata cannot override setSpeed(int) in Car
return type int is not compatible with void

이와 같은 에러가 발생한다.
그 이유는 Car 클래스에서 정의한 setSpeed() 메소드의 return 타입이 일치 하지 않기 때문이다.

// Car 클래스의 setSpeed() 메소드
public void setSpeed(int speed_change) {
	this.speed += speed_change;
	System.out.println(this.speed);
}

// Sonata 클래스의 setSpeed() 메소드
public int setSpeed(int speed) {
	this.speed += speed;

	if (this.speed > MAX_SPEED) {
		this.speed = MAX_SPEED;
	}

	return this.speed;
}

따라서 오버라이딩이 되지 않은 것이다. 오버라이딩을 할 시에는 반드시 위에 언급한 3가지 조건에 충족 되어야 한다.

올바른 오버라이딩(overriding) 예시

class Car {
    int speed = 0;

    public int setSpeed(int speed_change) {
        this.speed += speed_change;
        return this.speed;
    }
}

class Sonata extends Car {
    final int MAX_SPEED = 150;

    public int setSpeed(int speed) {
        this.speed += speed;

        if (this.speed > MAX_SPEED) {
            this.speed = MAX_SPEED;
        }

        return this.speed;
    }
}

public class CarOverridingTest {
    public static void main(String[] args) {
        Car car = new Car();
		car.setSpeed(30);

        Sonata sonata = new Sonata();
		sonata.setSpeed(180);
    }
}

2. 오버로딩(overloading)

오버라이딩은 부모 클래스에서 정의한 메소드를 상속 받은 자식 클래스에서 확장하는 개념이었다면 오버로딩(overloading)은 같은 클래스 내부에서 메소드를 확장하기 위한 개념이다. 오버로딩도 몇가지 조건을 충족해야 한다.

  • 메소드의 이름이 일치해야 함
  • 메소드 매개변수의 개수 또는 타입이 달라야 함 (개수가 같다면 타입, 타입이 같다면 개수를 다르게 해야함)
  • 메소드의 return 타입이 달라야 함

예제를 살펴보자.

  • 예제 시나리오
    Car 클래스에는 모델넘버(modelNum)와 모델넘버를 정의하는 메소드(setModel)가 있다. setModel()은 매개변수 정수 타입의 modeNum을 받아 인스턴스 멤버 modelNum에 대입하여 저장하고 인스턴스 멤버 modelNum을 return 한다. 그런데 모델넘버와 제조사가 함께 명시된 모델명도 정의하고 싶다.
class Car {
    int modelNum;

    public int setModel(int modelNum) {
        this.modelNum = modelNum;
        return this.modelNum;
    }
}

public class CarOverloadingTest {
    public static void main(String[] args) {
        Car car = new Car();
        car.setModel(7362);   // 7362
    }
}

main 메소드에서 인스턴스 메소드의 setModel()을 호출하면 결과적으로 인자로 넣은 7362가 Car 클래스 필드의 modelNum에 저장된다.

그 다음, 모델넘버와 제조사가 함께 명시된 모델명을 정의하기 위해서 오버로딩(overloading)을 활용할 수 있다. 기존의 매개변수 modelNum은 그대로 받지만 추가로 제조사명(brand)도 추가로 받아 더해서 인스턴스 멤버 String 타입의 model에 정의한다.

class Car {
    int modelNum;
    String model;

    public int setModel(int modelNum) {
        this.modelNum = modelNum;
        return this.modelNum;
    }

    public String setModel(int modelNum, String brand) {
        this.model = brand + modelNum;
        return this.model;
    }
}

public class CarOverloadingTest {
    public static void main(String[] args) {
        Car car = new Car();
        car.setModel(7362);   // 7362
        car.setModel(2407, "sonata");   // sonata2407
    }
}

main 메소드에서 setModel() 메소드를 호출하며 모델넘버(2407)와 제조사명("sonata")을 인자로 넣어주면 오버로딩된 메소드가 호출되어 각각의 매개변수로 들어가 결과적으로 필드의 model에 저장된다.

오늘 오버라이딩(overriding)과 오버로딩(overloading)에 대해 살펴 보았는데 내가 내린 정의는 이러하다.

오버라이딩(overriding)과 오버로딩(overloading)은 메소드(기능)의 재정의 또는 확장을 위한 개념이다. 다만 어디에서 어떤 용도로 사용 하느냐의 차이다.

0개의 댓글