JAVA (8) - 상속과 다형성
1. 개요
상속(Inheritance)과 다형성(Polymorphism)은 객체 지향의 핵심이라 불리는 대표적인 특성이다. 상속을 통해 기존 클래스의 자원을 재사용하고, 다형성을 통해 하나의 타입으로 여러 형태의 객체를 다룸으로써 유연하고 유지보수가 쉬운 프로그램을 작성할 수 있다.
2. 상속 (Inheritance)
상속은 기존의 클래스(부모 클래스 또는 상위 클래스)가 가진 필드와 메서드를 새로운 클래스(자식 클래스 또는 하위 클래스)가 물려받아 사용하는 것을 의미한다. 자바에서는 extends 키워드를 사용하여 상속을 구현한다.
// 부모 클래스
class Animal {
String name;
void eat() {
System.out.println("음식을 먹는다.");
}
}
// 자식 클래스
class Dog extends Animal {
void bark() {
System.out.println("멍멍 짖는다.");
}
}
- 코드의 재사용: 부모 클래스에서 정의된 메서드와 필드를 재작성하지 않고 그대로 사용할 수 있다.
- 단일 상속: 자바는 클래스 간 다중 상속을 허용하지 않는다. 즉,
extends뒤에는 하나의 부모 클래스만 지정할 수 있다.
모든 클래스의 최상위 부모 Object
자바에서 부모 클래스를 명시하지 않은 클래스는 java.lang.Object 클래스를 암묵적으로 상속받는다. 따라서 직접 상속 관계를 작성하지 않아도 모든 클래스는 Object의 자식 클래스가 된다.
class Person {
}
// 위 클래스는 다음과 같은 상속 관계를 가진다.
class Person extends Object {
}
Object는 모든 객체가 공통으로 사용할 수 있는 기본 메서드를 제공한다.
| 메서드 | 역할 |
|---|---|
toString() |
객체를 문자열로 표현한다. |
equals(Object obj) |
두 객체가 같은지 비교한다. |
hashCode() |
객체의 해시값을 반환한다. |
getClass() |
실행 중인 객체의 클래스 정보를 반환한다. |
Object 타입의 참조 변수에는 어떤 클래스의 객체든 담을 수 있다. 이는 모든 클래스가 Object를 상속하기 때문이며, 자바 다형성의 가장 넓은 형태에 해당한다.
Object object = new Dog();
toString(), equals(), hashCode() 등은 클래스의 특성에 맞게 오버라이딩할 수 있다. 특히 equals()와 hashCode()는 객체의 논리적 동등성을 정의할 때 함께 재정의해야 한다.
3. 메서드 오버라이딩 (Method Overriding)
부모 클래스로부터 물려받은 메서드의 동작을 자식 클래스에서 필요에 맞게 재정의하는 것을 메서드 오버라이딩이라고 한다.
오버라이딩을 할 때는 부모 클래스 메서드의 시그니처(메서드 이름, 매개변수 타입 및 개수, 반환 타입)가 동일해야 하며, @Override 애노테이션을 부여하여 컴파일 타임에 정확성을 검증하는 것이 권장된다.
class Cat extends Animal {
@Override
void eat() {
System.out.println("생선을 맛있게 먹는다."); // 부모의 eat()을 재정의
}
}
4. 다형성 (Polymorphism)
다형성은 ’여러 가지 형태를 가질 수 있는 능력’을 의미한다. 자바에서는 부모 클래스 타입의 참조 변수로 자식 클래스 인스턴스를 참조할 수 있는 성질로 나타난다.
Animal myPet = new Dog(); // 업캐스팅(Upcasting)
myPet.eat(); // Dog 객체의 오버라이딩된 메서드가 동작할 수 있음
- 업캐스팅(Upcasting): 자식 객체를 부모 타입의 변수에 할당하는 것으로, 별도의 형변환 연산자 없이 자동 변환된다.
- 다운캐스팅(Downcasting): 부모 타입을 다시 원래의 자식 타입으로 변환하는 것이다. 이때는 명시적 형변환 연산자가 필요하며, 안전한 변환을 위해
instanceof연산자를 활용하여 타입을 확인해야 한다.
if (myPet instanceof Dog) {
Dog myDog = (Dog) myPet; // 다운캐스팅
myDog.bark();
}
5. 다형성의 장점과 활용
다형성을 활용하면 하나의 배열이나 컬렉션에 서로 다른 자식 객체들을 담아 일괄적으로 처리할 수 있다. 또한 메서드의 매개변수 타입을 부모 타입으로 지정하면, 부모를 상속받은 모든 자식 객체를 전달받아 동작시킬 수 있어 확장성이 크게 향상된다.
public void makeAnimalEat(Animal animal) {
animal.eat(); // 전달되는 객체(Dog, Cat 등)에 따라 다르게 동작
}
6. 정리
상속은 기존 클래스의 속성과 기능을 물려받아 코드의 중복을 줄이고 계층 구조를 형성하는 메커니즘이다.
** 다형성**은 상속 관계와 메서드 오버라이딩을 바탕으로 부모 타입 하나로 여러 형태의 자식 객체를 유연하게 다룰 수 있게 해준다.