여기 그냥 자동차와 자동주행이 가능한 자동차가 있다고 가정하겠습니다.
AutomatedCar
클래스에서는 Car
클래스의 기본 기능들을 사용하기 위해 상속하고 자율 주행 모드를 전환하고 해제하는 기능을 추가하였습니다.
class Car {
void drive(); // 주행
void refuel(); // 주유
}
class AutomatedCar extends Car {
void enableAutonomousMode(); // 자율 주행 모드 전환
void disableAutonomousMode(); // 자융 주행 모드 해제
}
Main
public class Main {
public static void main(String[] args) {
Car car = new Car();
Car automatedCar = new AutomatedCar();
}
}
Car car = new AutomatedCar();
Car
클래스의 기본 기능인 drive()
, refuel()
밖에 사용 할 수 없습니다.업캐스팅, 다운캐스팅, 형변환에 대해서는 자세히 다루지는 않겠습니다.
위에 코드의 참조변수의 다형성은 사실 자식 클래스에 있는 기능은 사용도 못하고 부모 클래스의 기본 기능밖에 사용하지 못합니다. 좋아 보이는게 하나도 없는데 왜 쓰는 것일까요? 바로 자료형의 묶음입니다.
간단한 Animal
클래스를 상속받는 다양한 동물들이 있다고 가정하고 해당 동물들이 모두 울음소리를 출력하게 해보겠습니다.
// 동물을 나타내는 부모 클래스
class Animal {
protected String sound;
public Animal(String sound) {
this.sound = sound;
}
public void makeSound() {
System.out.println(sound);
}
}
// 각각의 동물을 나타내는 자식 클래스들
class Dog extends Animal {
public Dog() {
super("멍멍!");
}
}
class Cat extends Animal {
public Cat() {
super("야옹!");
}
}
class Duck extends Animal {
public Duck() {
super("꽥꽥!");
}
}
public class PolymorphismExample {
public static void main(String[] args) {
// 각 동물의 객체를 생성하고 울음 소리 출력
Dog myDog = new Dog();
myDog.makeSound();
Cat myCat = new Cat();
myCat.makeSound();
Duck myDuck = new Duck();
myDuck.makeSound();
}
}
makeSound()
메서드를 출력 해주는 방법 밖에 없습니다.Animal
부모 클래스에 상속 관계를 이용하여 각 타입을 Animal
클래스로 묶는다면public class PolymorphismExample {
public static void main(String[] args) {
// 다형성을 활용하여 여러 동물을 하나의 배열에 담음
Animal[] animals = new Animal[3];
animals[0] = new Dog();
animals[1] = new Cat();
animals[2] = new Duck();
// 배열을 순회하면서 각 동물의 소리를 출력
for (Animal animal : animals) {
animal.makeSound();
}
}
}
다형성은 변수의 타입 뿐만 아니라 매개변수에서도 찾아 볼 수 있습니다.
// 동물을 나타내는 인터페이스
interface Animal {
void makeSound();
}
// 다양한 동물을 나타내는 클래스들
class Dog implements Animal {
@Override
public void makeSound() {
System.out.println("멍멍!");
}
}
class Cat implements Animal {
@Override
public void makeSound() {
System.out.println("야옹!");
}
}
// 동물 소리를 출력하는 유틸리티 클래스
class AnimalSoundUtil {
// 매개변수로 Animal 인터페이스를 구현한 객체를 받아 소리를 출력
public static void makeAnimalSound(Animal animal) {
animal.makeSound();
}
}
// 실행 클래스
public class InterfaceParameterPolymorphismExample {
public static void main(String[] args) {
// 다형성을 이용하여 다양한 동물 객체를 매개변수로 전달
AnimalSoundUtil.makeAnimalSound(new Dog()); // Dog 객체 전달
AnimalSoundUtil.makeAnimalSound(new Cat()); // Cat 객체 전달
}
}
메서드를 확장하거나 재정의하는 overloading / overriding도 메서드가 다형해 지기 때문에 다형성의 특징 중 하나로 볼 수 있습니다.
class Animal {
public void makeSound() {
System.out.println("동물 소리");
}
public void specialAction() {
System.out.println("동물의 특별한 행동");
}
public void specialAction(String action) {
System.out.println("동물의 특별한 행동: " + action);
}
}
class Dog extends Animal {
@Override
public void makeSound() {
System.out.println("멍멍!");
}
@Override
public void specialAction() {
System.out.println("개의 특별한 행동: 짖기");
}
public void specialAction(int distance) {
System.out.println("개의 특별한 행동: " + distance + "m 뛰기");
}
}
class Cat extends Animal {
@Override
public void makeSound() {
System.out.println("야옹!");
}
@Override
public void specialAction() {
System.out.println("고양이의 특별한 행동: 발톱 갈기");
}
public void specialAction(String action, int times, boolean loud) {
if (loud) {
System.out.println("고양이의 특별한 행동: " + action + " " + times + "번 반복 (크게 소리 내어)");
} else {
System.out.println("고양이의 특별한 행동: " + action + " " + times + "번 반복");
}
}
}
public class MethodPolymorphismExample {
public static void main(String[] args) {
Dog myDog = new Dog();
Cat myCat = new Cat();
// 각 동물의 소리 출력
myDog.makeSound();
myCat.makeSound();
// 각 동물의 특별한 행동 출력
// 오버 라이딩
myDog.specialAction();
myCat.specialAction();
// 각 동물의 특별한 오버로딩 메서드 호출
myDog.specialAction(3);
myCat.specialAction("뛰기", 3, true);
}
}
참고