ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Java] 다형성과 타입 변환
    언어/Java 2021. 1. 9. 17:44

    다형성(Polymorphism)

    다형성은 동일한 방법으로 메소드를 실행하지만 실행 결과는 다양하게 나오도록 하는 성질입니다. 예를 들어 자동차가 타이어를 사용하는 방법은 동일하지만 어떤 타이어를 사용하느냐에 따라 성능이 달라질 수 있습니다.

    다형성을 구현하려면 메소드 재정의와 타입 변환이 필요합니다.

    자동 타입 변환

    자동 타입 변환은 클래스, 필드, 매개 변수에서 발생합니다.

    클래스

    클래스의 변환은 상속 관계에 있는 클래스 사이에서도 발생합니다. 자식은 부모 타입으로 자동 타입 변환이 가능합니다.

    자동 타입 변환

    [부모 타입] 변수 = [자식타입];


    public class Car {
    }
    
    
    public class Volvo extends Car {
    }
    
    // 1
    Car volvo = new Volvo();
    
    // 2
    Volvo volvo2 = new Volvo();
    Car car = volvo2;


    위의 2번째와 같이 선언했을 때, car 변수는 Car 객체의 메모리 주소를 참조하는 것이 아닌 volvo2와 동일하게 Volvo 객체의 메모리 주소를 참조합니다. 

    volvo2 == car // true


    부모 타입으로 자동 타입이 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능합니다. 비록 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정됩니다. 예외적으로 메소드가 자식 클래스에서 재정의됐다면 자식 클래스의 메소드가 대신 호출됩니다. 이 것이 가능한 것은 다형성과 관련이 있기 때문입니다.

    public class Car {
        public void m1() {}
        public void m2() {}
    }
    
    
    public class Volvo extends Car {
        public void m2() {}
        public void m3() {}
    }
    
    
    Car volvo = new Volvo();
    
    volvo.m1();
    volvo.m2(); // Volvo 객체의 m2 호출
    volvo.m3(); // 호출 불가능

    필드

    필드도 위 클래스와 같이 자동 타입 변환이 진행됩니다. 필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 필드 사용 결과가 달라질 수 있습니다.

    public class Tire {
        public String location;
    
        public Tire(String location) {
            this.location = location;
        }
    
        public void roll() {
            System.out.println("기본 타이어 굴러가는 중...");
        }
    }
    
    
    public class MichelinTire extends Tire{
        public MichelinTire(String location) {
            super(location);
        }
    
        @Override
        public void roll() {
            System.out.println(location+" 굴러가는 중...");
        }
    }
    
    
    public class Car {
        Tire flTire = new Tire("전방좌측");
        Tire frTire = new Tire("전방우측");
        Tire rlTire = new Tire("후방좌측");
        Tire rrTire = new Tire("후방우측");
    
        public void startUp() {
            flTire.roll();
            frTire.roll();
            rlTire.roll();
            rrTire.roll();
    
            System.out.println("부릉부릉");
        }
    }
    
    
    Car volvo = new Volvo();
    volvo.startUp();
    volvo.flTire = new MichelinTire("전방좌측 미쉐린 타이어");
    volvo.flTire.roll();
    
    
    // 기본 타이어 굴러가는 중...
    // 기본 타이어 굴러가는 중...
    // 기본 타이어 굴러가는 중...
    // 기본 타이어 굴러가는 중...
    // 부릉부릉
    // 전방좌측 미쉐린 타이어 굴러가는 중...

    매개 변수

    클래스, 필드와 마찬가지로 매개 변수도 자동 변환이 가능합니다.

    public class Car {
        public void startUp() {
            System.out.println("부릉부릉");
        }
    }
    
    
    public class Volvo extends Car {
        public void startUp() {
            System.out.println("볼보 부릉부릉");
        }
    }
    
    
    public class Driver {
        public void drive(Car car) {
            car.startUp();
        }
    }
    
    
    Driver driver = new Driver();
    Volvo volvo = new Volvo();
    
    driver.drive(volvo); // Car 객체로 변환
    
    
    // 볼보 부릉부릉

    강제 타입 변환

    강제 타입 변환은 보통 부모 타입을 자식 타입으로 변환할 때 사용합니다. 하지만 모든 부모 타입에서 자식 타입으로 강제 변환 할 수 있지는 않습니다. 자식 타입이 부모 타입으로 자동 타입 변환이 일어난 다음, 다시 자식타입으로 변환할 때도 사용할 수 있습니다. 

    Car volvo = new Volvo(); // 자동 타입 변환
    Volvo volvo2 = (Volvo) volvo; // 강제 타입 변환


    자식 타입이 부모 타입으로 자동 타입 변환하면 부모에 선언된 필드와 메소드만 사용할 수 있습니다. 만약 자식 선언에 선언된 필드와 메소드를 사용해야 한다면 강제 타입 변환으로 다시 자식 타입으로 변환한 다음 사용해야 합니다.

    public class Car {
        String f1;
        void m1() {}
        void m2() {}
    }
    
    
    public class Volvo extends Car {
        String f2;
        void m2() {}
        void m3() {}
    }
    
    
    Car volvo = new Volvo(); // 자동 타입 변환
    
    volvo.f1 = "aa";
    volvo.m1();
    volvo.m2(); // Volvo 객체의 m2() 호출
    volvo.f2 = "bb"; // 호출 X
    volvo.m3(); // 호출 X
    
    Volvo volvo2 = (Volvo) volvo;
    
    volvo2.f2 = "vv";
    volvo2.m3();


    강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 아래와 같이 처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없습니다.

    Car car = new Car();
    Volvo volvo = (Volvo) car; // 강제 타입 변환 X


    부모 변수가 참조하는 객체가 부모인지 자식인지 확인하는 방법은 instanceof 연산자를 사용하면 됩니다. instanceof는 어떤 객체가 어떤 클래스의 인스턴스인지 확인할 때 사용합니다. 

    bool result = {객체} instanceof {타입}


    위 연산자를 사용해 입력받은 객체가 부모인지 자식인지 판별한 다음 자식 객체일 경우만 강제 타입 변환하는 로직을 만들 수 있습니다.

    public void m(Car car) {
        if (car instanceof Volvo) {
            Volvo volvo = (Volvo) car;
    }


    댓글