상속(Inheritance)과 다형성(Polymorphism)은 객체 지향의 핵심이라 불리는 대표적인 특성이다. 상속을 통해 기존 클래스의 자원을 재사용하고, 다형성을 통해 하나의 타입으로 여러 형태의 객체를 다룸으로써 유연하고 유지보수가 쉬운 프로그램을 작성할 수 있다.
상속은 기존의 클래스(부모 클래스 또는 상위 클래스)가 가진 필드와 메서드를 새로운 클래스(자식 클래스 또는 하위 클래스)가 물려받아 사용하는 것을 의미한다. 자바에서는 extends 키워드를 사용하여 상속을 구현한다.
// 부모 클래스
class Animal {
String name;
void eat() {
System.out.println("음식을 먹는다.");
}
}
// 자식 클래스
class Dog extends Animal {
void bark() {
System.out.println("멍멍 짖는다.");
}
}
extends 뒤에는 하나의 부모 클래스만 지정할 수 있다.부모 클래스로부터 물려받은 메서드의 동작을 자식 클래스에서 필요에 맞게 재정의하는 것을 메서드 오버라이딩이라고 한다.
오버라이딩을 할 때는 부모 클래스 메서드의 시그니처(메서드 이름, 매개변수 타입 및 개수, 반환 타입)가 동일해야 하며, @Override 애노테이션을 부여하여 컴파일 타임에 정확성을 검증하는 것이 권장된다.
class Cat extends Animal {
@Override
void eat() {
System.out.println("생선을 맛있게 먹는다."); // 부모의 eat()을 재정의
}
}
다형성은 '여러 가지 형태를 가질 수 있는 능력'을 의미한다. 자바에서는 부모 클래스 타입의 참조 변수로 자식 클래스 인스턴스를 참조할 수 있는 성질로 나타난다.
Animal myPet = new Dog(); // 업캐스팅(Upcasting)
myPet.eat(); // Dog 객체의 오버라이딩된 메서드가 동작할 수 있음
instanceof 연산자를 활용하여 타입을 확인해야 한다.if (myPet instanceof Dog) {
Dog myDog = (Dog) myPet; // 다운캐스팅
myDog.bark();
}
다형성을 활용하면 하나의 배열이나 컬렉션에 서로 다른 자식 객체들을 담아 일괄적으로 처리할 수 있다. 또한 메서드의 매개변수 타입을 부모 타입으로 지정하면, 부모를 상속받은 모든 자식 객체를 전달받아 동작시킬 수 있어 확장성이 크게 향상된다.
public void makeAnimalEat(Animal animal) {
animal.eat(); // 전달되는 객체(Dog, Cat 등)에 따라 다르게 동작
}
상속은 기존 클래스의 속성과 기능을 물려받아 코드의 중복을 줄이고 계층 구조를 형성하는 메커니즘이다.
다형성은 상속 관계와 메서드 오버라이딩을 바탕으로 부모 타입 하나로 여러 형태의 자식 객체를 유연하게 다룰 수 있게 해준다.