상속과 컴포지션(구성)은 객체 지향 프로그래밍에서 중요한 두 가지 설계 원칙입니다. 이 글에서는 상속과 다형성을 활용한 코드를 살펴보고, 이를 통해 이해할 수 있는 개념들을 자세하게 설명하겠습니다.
코드 설명: 상속과 다형성
먼저, 아래 코드를 통해 상속과 다형성에 대해 알아보겠습니다.
abstract class Car { // 추상 클래스 Car
abstract void run(); // 추상 메서드 run
}
class Sonata extends Car { // Car 클래스를 상속받은 Sonata 클래스
@Override
void run() {
System.out.println("소나타 달린다");
}
}
class Genesis extends Car { // Car 클래스를 상속받은 Genesis 클래스
@Override
void run() {
System.out.println("제네시스 달린다");
}
}
public class Mem02 {
public static void main(String[] args) {
Car s = new Sonata(); // Sonata 객체를 Car 타입으로 생성
s.run(); // Sonata의 run() 메서드 호출
Car g = new Genesis(); // Genesis 객체를 Car 타입으로 생성
g.run(); // Genesis의 run() 메서드 호출
}
}
1. 상속(Inheritance)
상속은 객체 지향 프로그래밍에서 기존 클래스를 기반으로 새로운 클래스를 정의하는 방법입니다. 여기서
Car
클래스는 추상 클래스(abstract class)로, Sonata
와 Genesis
클래스는 Car
클래스를 상속받아 각각의 기능을 정의합니다.- 추상 클래스(Car): 추상 클래스는
new
키워드를 사용해 인스턴스를 생성할 수 없습니다.Car
클래스는 추상 메서드run()
을 가지고 있으며, 이 메서드는 구체적인 동작이 정의되어 있지 않습니다. 대신,Sonata
와Genesis
클래스가 이 메서드를 구체적으로 구현(override)하게 됩니다.
- 구체 클래스(Sonata, Genesis):
Sonata
와Genesis
클래스는Car
클래스를 상속받아run()
메서드를 재정의(override)합니다. 이로써 각각의 클래스는 자신만의 동작을 가지게 됩니다.
2. 다형성(Polymorphism)
다형성은 동일한 인터페이스나 부모 클래스를 통해 다양한 객체를 다룰 수 있는 능력입니다. 여기서는
Car
타입의 변수가 Sonata
와 Genesis
객체를 참조할 수 있는 것이 다형성의 예입니다.Car s = new Sonata();
Car g = new Genesis();
위 코드에서
Car
타입의 변수 s
와 g
는 각각 Sonata
와 Genesis
객체를 참조합니다. 다형성 덕분에 Car
타입으로 선언된 변수에 서로 다른 구체 클래스를 할당할 수 있습니다.- 동적 바인딩(Dynamic Binding): 메서드 호출이 런타임에 실제 객체의 타입에 따라 결정되는 것을 동적 바인딩이라고 합니다. 위 예제에서
s.run()
을 호출할 때,Car
클래스의run()
메서드를 호출하는 것이 아니라,Sonata
클래스에서 재정의된run()
메서드가 호출됩니다. 이는 프로그램 실행 중에s
가 실제로Sonata
객체를 참조하고 있기 때문입니다. 마찬가지로g.run()
은Genesis
클래스의run()
메서드를 호출합니다.
상속의 장점
- 코드 재사용: 공통된 기능을 부모 클래스에 정의하고, 이를 상속받아 재사용할 수 있습니다. 예를 들어,
Car
클래스에 추가적인 공통 기능을 정의하면Sonata
와Genesis
는 이를 자동으로 상속받게 됩니다.
- 유지보수성: 상속을 통해 변경이 필요할 때 부모 클래스만 수정하면 모든 자식 클래스에 적용되므로 코드 수정이 용이합니다.
- 다형성 활용: 부모 클래스 타입의 변수로 여러 자식 클래스를 다룰 수 있어 코드의 유연성이 높아집니다.
Share article