개발 블로그
article thumbnail
Published 2023. 4. 7. 15:27
상속 Java

이번에는 객체지향프로그래밍에서 중요한 개념 중 하나인 '상속'에 대해서 알아보고

실제 Java에서는 어떻게 상속을 할 수 있는지 알아보도록 하겠습니다.

추상화

상속에 대해 이야기 하기 전에 먼저 '추상화'라는 개념부터 알아야 합니다. 

출처 : 위키백과

여기서 중요한 설명은 '핵심적인 개념 또는 기능을 간추려 내는 것'이라는 말입니다.

 

객체지향 프로그래밍에서 말하는 추상화도 이와 같은 맥락을 지닙니다.

 

"객체들이 공통으로 갖는 핵심적인 속성이나 기능을 간추려 정의하는 것"

 

예를 들어 자동차와 자전거를 생각해봅시다.

이 객체들은 모두 '전진', '좌회전', '우회전' 등의 기능을 갖고 있습니다.

 

Class Car {
    void forward(){}
    void left(){}
    void right(){}
    ...
}

Class Bicycle {
    void forward(){}
    void left(){}
    void right(){}
    ...
}

 

여기서 공통적으로 갖는 속성이나 기능을 간추려서 '이동수단'이라는 상위 개념으로 정의한다면 이것이 바로 '추상화'입니다.

Class Vehicle {
    void forward(){}
    void left(){}
    void right(){}
}

 

상속

우리가 기껏해서 고민해서 추상화를 했는데 여전히 코드는 어떤 상태인가요?

Class Car {
    void forward(){}
    void left(){}
    void right(){}
    ...
}

Class Bicycle {
    void forward(){}
    void left(){}
    void right(){}
    ...
}

Class Vehicle {
    void forward(){}
    void left(){}
    void right(){}
}

이동수단이라면 당연히 갖는 기능들 '전진  좌회전 우회전'이 모든 클래스에 선언되어 있습니다.

 

앞으로 이동수단이 더 추가되면 그 때마다 또 다시 'void forward(), void backward() ~' 를 작성하고 있다면 얼마나 비효율적인가요?

 

이런 비효율적인 문제를 해결할 수 있는 것이 바로 '상속'의 개념입니다.

 

 

다른 클래스의 속성(필드)이나 기능(메서드)를 물려받아 사용하는 것

 

Java 에서는 extends 라는 키워드 하나로 다른 클래스로부터 필드와 메서드를 물려받아 사용할 수 있습니다.

그럼 상속을 이용해 위의 코드를 다시 작성해보겠습니다.

 

class Vehicle {
    void forward(){}
    void left(){}
    void right(){}
}

class Car extends Vehicle {
    ...
}

class Bicycle extends Vehicle {
    ...
}

 

훨씬 더 코드가 간결해진 것을 볼 수 있죠?

 

 

부모 클래스, 자식 클래스

물려 받는 클래스를 '자식 클래스' 물려 주는 클래스를 '부모 클래스'라고 칭합니다.

위 예제에서는 Vehicle 이 부모 클래스가 되겠고 Car 와 Bicycle 이 Vehicle 의 자식 클래스가 되겠죠?

 

extends 라는 키워드를 이용하면 상속이 가능하다고 했는데 그럼 실제로 자식 클래스로 객체를 만들고 부모 클래스에서 정의된 멤버를 가져다 쓰는 과정은 어떻게 이루어질까요?

 

Car car = new Car();
Bicycle bicycle = new Bicycle();

car.forward();
bicycle.forward();

마치 원래부터 자식 클래스에 정의된 것 마냥 바로 사용할 수 있습니다.

 

그런데 이 과정은 실제로는 부모 클래스로부터 만들어진 객체의 메서드를 참조하는 방식으로 이루어집니다.

 

Car 클래스를 통해 객체를 생성하게 되면 먼저 Vehicle 클래스 객체가 생성되고 Car 클래스 객체는 이를 참조하고 있는 형태가 됩니다.

 

그래서 코드로 보기에는 car.forward() 하면 car 인스턴스의 forward 메서드를 실행하는 것처럼 보이지만

실제로는 부모 클래스 객체의 forward() 메서드를 참조해서 실행되고 있는 것입니다.

 

 

메서드 오버라이딩

메서드 오버라이딩은 자식 클래스에서 부모 클래스의 메서드를 덮어 쓰는 것을 말합니다.

 

Vehicle 클래스에 정의된 forward() 메서드를 다음과 같이 만들어보겠습니다.

Class Vehicle {
    void forward() {
        System.out.println("앞으로 이동합니다.");
    }
}

그럼 이를 상속하는 Car 클래스나 Bicycle 클래스로 만든 객체들도 forward() 메서드를 실행하면

앞으로 이동합니다.

이런 메시지를 출력하게 되겠죠?

 

그런데 자동차가 앞으로 이동하려면 액셀을 밟아야 하고 자전거가 앞으로 이동하려면 페달을 밟아야 합니다.

 

이처럼 부모 클래스에서 상속 받아온 메서드라고 해도 자식 클래스에 따라서는 메서드를 수정할 필요가 있는데 이때 하는 것이 바로 '메서드 오버라이딩'입니다.

 

Class Car {
    @Override // annotation인데 주석이라고 생각하면 됩니다.
    void forward() {
        System.out.println("악셀을 밟습니다.");
        System.out.println("전진합니다.");
    }
}

Class Bicycle {
    @Override
    void forward() {
        System.out.println("페달을 밟습니다.");
        System.out.println("전진합니다.");
    }
}

 

이렇게 되면 이제 자식 클래스 객체들을 통해 forward() 메서드를 호출할 때 더 이상 부모 클래스 객체의 forward() 를 참조하지 않고 자식 클래스 객체 본연의 forward() 메서드를 실행하게 됩니다.

 

Car car = new Car();
Bicycle bicycle = new Bicycle();

car.forward();
bicycle.forward();

/*
악셀을 밟습니다.
전진합니다.
페달을 밟습니다.
전진합니다.
*/

 

'Java' 카테고리의 다른 글

비트 연산자(<<, >>, &, |, ^, ~)  (0) 2023.09.19
스레드 동기화(synchronized)  (0) 2023.04.12
접근제어자와 Getter & Setter  (0) 2023.04.06
클래스, 객체, 인스턴스  (0) 2023.04.06
얕은 복사 vs 깊은 복사  (0) 2023.04.04
profile

개발 블로그

@하얀.손

포스팅이 좋았다면 "좋아요❤️" 또는 "구독👍🏻" 해주세요!