Java-객체지향 프로그래밍-다형성
다형성
객체지향 프로그래밍의 대표요소 중 다형성에 대해서 알아보자.
다형성이란, 하나의 객체가 여러가지 형태를 가질 수 있는 성질이다.
더 나아가, 자바에서 다형성이란 상위 클래스의 참조 변수로 하위 클래스의 참조 변수를 다루거나 동일한 이름을 가진 여러 형태의 메서드를 만들 수 있는 등 다양한 형태를 가질 수 있는 성질이다.
- 업캐스팅, 다운캐스팅, 오버라이딩, 오버로딩등이 다형성에 속해 있다.
그럼 코드로 한번 다형성에 대해서 살펴보자.
class Main {
public static void main(String[] args) {
Car car = new Car();
SmartCar smartCar = new SmartCar();
Car smartCar2 = new SmartCar(); //업캐스팅
// SmartCar smartCar3 = new Car();//다운캐스팅
}
}
class Car{
void powerOn(){
System.out.println("시동이 걸렸습니다.");
}
void powerOff(){
System.out.println("시동을 껐습니다.");
}
}
class SmartCar extends Car{
void autoDrive(){
System.out.println("자율주행 모드입니다.");
}
void chargeBattery(){
System.out.println("배터리를 충전합니다.");
}
}
위의 코드는 상속에서 나타나는 대표적인 다형성이다.
일반적으로 새로운 객체를 생성할때는 동일한 클래스 타입의 참조 변수를 생성하여 사용해왔다.
하지만 만약 해당 두 객체가 상속 관계에 있다면,
Car smartCar2 = new SmartCar();
와 같이 상위 클래스 타입으로 하위 클래스 타입을 받아 초기화 할 수 있다.
이를 업캐스팅(UpCasting)
이라고 한다.
SmartCar smartCar3 = new Car();
위 코드는 어떨까?
코드를 입력해보면, 알겠지만 에러를 발생할 것이다.
하위클래스에서 상위클래스로 변환하기 위해선
SmartCar smartCar3 = (SmartCar) new Car();
과 같이 상위클래스 타입을 명시해 주어야한다.(캐스팅 연산자)
이것을 다운캐스팅(DownCasting)
이라고 한다.
다만, 위의 코드는 다운캐스팅 문법의 예시일뿐 실제로 해당 코드를 작성 후 실행 시 런타임 에러를 반환한다.
이유는 다운캐스팅의 경우에는 업캐스팅된 객체를 다운캐스팅하여 기존의 타입으로 변환시킬때 사용되기 때문이다.
위의 객체는 업캐스팅되어 생성된 객체가 아니므로 오류를 반환하게 된다.
그렇다면, 다형성이 왜 필요할까?
다형성을 이용하면, 타입들을 묶어서 처리할 수 있고, 타입을 묶어서 처리한다면 코드가 좀더 간결해지고 유지보수에 용이해질 것이다.
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<Car> car = new ArrayList<Car>();
car.add(new Car());
ArrayList<SmartCar> smartCar = new ArrayList<SmartCar>();
smartCar.add(new SmartCar());
ArrayList<SportCar> sportCar = new ArrayList<SportCar>();
sportCar.add(new SportCar());
}
}
class Car{
}
class SmartCar{
}
class SportCar{
}
위의 코드는 다형성이 적용되지 않은 코드이다.
다형성이 적용되지 않았기때문에 타입에 맞는 ArrayList를 생성해주어야 하며, 개별의 관리가 필요하다.
import java.util.ArrayList;
class Main {
public static void main(String[] args) {
ArrayList<Car> car = new ArrayList<Car>();
car.add(new Car());
car.add(new SmartCar());
car.add(new SportCar());
}
}
class Car{
}
class SmartCar extends Car{
}
class SportCar extends Car{
}
하지만, 위와 같이 다형성을 이용하면 하나의 타입으로 묶어서 사용하고 코드가 간결해지는 편리함이 있다.
다형성의 활용법
class Main {
public static void main(String[] args) {
Customer customer = new Customer();
customer.buySnack(new Bread());
System.out.println("잔액은 " + customer.money + "원 입니다.");
}
}
class Snack{
int price;
public Snack(int price){
this.price = price;
}
}
class Bread extends Snack{
public Bread() {
super(3000);
}
@Override
public String toString(){return "빵";}
}
class Candy extends Snack{
public Candy() {
super(1500);
}
@Override
public String toString(){return "캔디";} //오버라이딩을 통한 다형성
}
class Customer{
int money = 100000;
void buySnack(Snack snack){ //매개변수의 다형성
money -= snack.price;
System.out.println(snack + "을 구입했습니다.");
}
}
//출력
빵을 구입했습니다.
잔액은 97000원 입니다.
다형성을 사용하여 매개변수와 오버라이딩 등 다양한 다형성을 적용하여 코드를 구현한 모습이다.
void buyBread(Bread bread){ //
money -= bread.price;
}
void buyCandy(Candy candy){
money -= candy.price;
}
만약 다형성이 없었더라면, 위와같은 메서드들을 매번 정의해주었어야 할 것이며, 지금은 두,세개정도의 메서드지만 실제 현업에서는 무수히 많은 메서드가 존재하므로… 코드 가독성은 훨씬 떨어지게 될 것이다.
정리
- 다형성은 객체가 다양한 형태의 타입으로 변환될 수 있는 것(상속의 관계에서만)
- 대표적으로 업캐스팅, 다운캐스팅, 메서드 오버로딩, 메서드 오버라이딩, 인터페이스, 추상메소드, 추상클래스 등이 있다.
- 업 캐스팅시에는 형변환 되는 타입의 생략이 가능하지만, 다운캐스팅 시에는 반드시 타입앞에 캐스팅연산자(상위클래스)를 기입해야한다.