티스토리 뷰

객체지향의 특징 중 다형성이 상속과 인터페이스에서 각각 어떻게 구현되는지 알아보려고 한다.


타입 변환

상속과 인터페이스의 다형성에서 동일하게 적용되는 기술은 타입 변환이다.

타입 변환에는 두 가지 방법이 있다.

Upcasting(자동 타입 변환) 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말한다.

상속에서는 자식 클래스가 부모 클래스의 타입으로, 인터페이스에서는 구현 클래스가 인터페이스 타입으로 변환되는 것이다.

Downcasting(강제 타입 변환) 개발자가 명시적으로 선언해야하는 타입 변환 과정이다.

상속에서는 부모 클래스가 자식 클래스 타입으로, 인터페이스에서는 인터페이스 타입이 구현 클래스로 변환되는 것이다.

 

강제 타입 변환 시 거쳐야 하는 과정이 있는데, 바로 객체 타입 확인이다.

instanceOf 연산자를 사용하여 객체의 타입을 확인 후, 안전하게 강제 타입 변환을 진행해야한다. 만약 타입이 일치하지 않는 경우 강제 타입 변환을 시도하면 ClassCastException 이 발생할 수 있다.

 

상속의 다형성

상속은 부모 클래스와 자식 클래스 관계에서 자식 클래스가 부모 클래스의 속성과 기능을 그대로 물려 받는 것이다. 상속에서 다형성은 부모 클래스 타입으로 자식 클래스 객체를 참조할 수 있다는 것이다.

public class Car {
    void forward() {
        System.out.println("차가 전진합니다");
    }
    
    void reverse() {
        System.out.println("차가 후진합니다");
    }
}

public class HybridCar extends Car {

    private boolean isElectricMode;
    
    public HybridCar() {
        isElectricMode = false;
    }
    
    @Override
    void forward() {
        System.out.println("하이브리드 차가 전진합니다");
    }
    
    void switchElectricMode() {
        if (!isElectricMode) {
            isElectricMode = true;
        }
    }
}

public class Main {
    public static void main(String[] args) {
        //Upcasting
        Car car = new HybridCar();
        car.forward(); //하이브리드 차가 전진합니다. 출력
        car.reverse(); //차가 후진합니다. 출력

        //Downcasting
        HybridCar hybridCar = (HybridCar) car;
        hybridCar.switchElectricMode();
    }
}

상속에서 다형성은 다양한 객체를 부모 클래스라는 동일한 타입으로 처리할 수 있다.

상속 관계에서는 자식 클래스의 객체를 부모 클래스 타입으로 참조할 수 있도록 선언해서 사용한다. 이는 자식 클래스의 객체를 생성한 후에 부모 클래스 타입 변수에 저장해서 부모 타입으로 참조한다는 것이다.

이 때, 부모 타입으로 Upcasting(자동 타입 변환)이 이루어지는데 부모 클래스에 선언된 필드와 메서드에 접근이 가능하다. 또한 자식 클래스가 부모 클래스의 메서드를 재정의 했다면 부모 클래스의 메서드를 호출해도 자식 클래스의 메서드가 호출된다.

만약 자식 클래스에 선언된 멤버를 꼭 사용해야한다면 Downcasting(강제 타입 변환) 을 해야한다. 이 경우에는 부모 클래스의 필드와 메서드에 접근을 할 수 없다.

 

인터페이스에서의 다형성

클래스가 구현해야 하는 메서드의 집합을 정의하는 방법이다. 

여러 클래스가 동일한 인터페이스를 구현할 수 있는 것으로 동일한 타입(인터페이스)의 객체가 다양한 형태로 동작하는 것이 인터페이스에서의 다형성이다.

public interface Drivable {
    void drive();
}

public class Car implements Drivable {
    @Override
    public void drive() {
        System.out.println("자동차가 주행합니다");
    }
}

public class Bike implements Drivable {
    @Override
    public void drive() {
        System.out.println("자전거가 주행합니다");
    }
}

public class Main {
    public static void main(String[] args) {
        Drivable car = new Car();
        Drivable bike = new Bike();
        
        car.drive(); // 자동차가 주행합니다 출력
        bike.drive(); // 자전거가 주행합니다 출력
    }
}

인터페이스를 통해 공통된 기능을 정의하지만, 각 클래스에서의 구현은 다르게 정의된다.

'Language > Java' 카테고리의 다른 글

추상클래스와 인터페이스  (0) 2024.10.22
싱글톤(Singleton)에 대하여  (0) 2024.10.20
인스턴스 멤버와 정적 멤버  (0) 2024.10.18
final 키워드  (0) 2024.10.18
생성자와 오버로딩  (0) 2024.10.18
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
글 보관함