본문 바로가기

프로그래밍/Java

타입 변환과 다형성

다형성

사용방법은 동일하지만

다양한 객체를 이용해서

다양한 실행 결과가 나오도록하는 성질

ex) 팥 붕어빵, 슈크림 붕어빵

 

public class A{
}
public class B extends A{
}
public class Test{
    public static void main(String[] args){
        B b = new B();
        A a = b;
        A aa = new B();
    }
}

자식 타입은 부모 타입으로 자동 형변환 가능

 

바로 부모 자식 관계가 아니라

상속 계층에 속하면 자동 타입 변환 가능

 

class A{}

class B extends A{}

class C extends B{}

class D extends A{}

class E extends D{}

public class test{
    public static void main(String[] args){
        B b = new B();
        C c = new C();
        D d = new D();
        E e = new E();
        
        A a1 = b;
        A a2 = c;
        A a3 = d;
        A a4 = e;
        
        B b1 = c;
        D d1 = e;
        
        //B b3 = e; ERROR
        //C c2 = d; ERROR
    }
}

 

 

부모 타입으로 형변환 된 이후에는

부모 클래스에 선언된 필드와 메소드만 접근 가능

비록 변수는 자식 객체를 참조 하지만

변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정

예외

메소드가 자식 클래스에서 재정의되었다면

자식 클래스의 메소드가 대신호출

 

public class Parent{
    void method1(){
        System.out.println("Parent Method1");
    }
    void method2(){
        System.out.println("Parent Method2");
    }
    
}
public class Child extends Parent{
    @Override
    void method2(){
        System.out.println("Child method2");
    }
    void method3(){
        System.out.println("Child method3");
    }
}
public class Test{
    public static void main(String[] args){
        Child child = new Child();
        Parent parent = child;
        parent.method1();
        parent.method2();
        //parent.method3(); ERROR
    }
}

Test 실행 결과

 

필드의 다형성 예제

부모 클래스를 상속하는 자식 클래스는 사용법이 동일

자식 클래스는 부모 클래스의 메소드를 재정의 함으로써

더 우수한 결과 출력 가능

자식 타입을 부모 타입으로 변환 가능

 

Tire

public class Tire{
    int maxRotation;//최대 회전수
    int accumulatedRotation;//누적 회전수
    String location;// 타이어의 위치
    
    Tire(String location, int maxRotation){
        this.location = location;
        this.maxRotation = maxRotation;
    }
    
    boolean roll(){
        ++accumulatedRotation;
        if(accumulatedRotation<maxRotation){
            System.out.println(location+"Tire 수명: "+(maxRotation-accumulatedRotation));
            return true;
        }
        else{
            System.out.println("*** "+location+" Tire 펑크 ***");
            return false;
        }
    }
}

 

KumhoTire

public class KumhoTire extends Tire{
    KumhoTire(String location, int maxRotation){
        super(location, maxRotation);
    }
    
    @Override
    boolean roll(){
        ++accumulatedRotation;
        if(accumulatedRotation<maxRotation){
            System.out.println(location+"KumhoTire 수명: "+(maxRotation-accumulatedRotation));
            return true;
        }
        else{
            System.out.println("*** "+location+" KumhoTire 펑크 ***");
            return false;
        }
    }
}

 

HankookTire

public class HankookTire extends Tire{
    HankookTire(String location, int maxRotation){
        super(location, maxRotation);
    }
    
    @Override
    boolean roll(){
        ++accumulatedRotation;
        if(accumulatedRotation<maxRotation){
            System.out.println(location+"HankookTire 수명: "+(maxRotation-accumulatedRotation));
            return true;
        }
        else{
            System.out.println("*** "+location+" HankookTire 펑크 ***");
            return false;
        }
    }
}

 

Car

public class Car{
    Tire FLtire = new Tire("앞왼쪽",6);
    Tire FRtire = new Tire("앞오른쪽",2);
    Tire BLtire = new Tire("뒤왼쪽",3);
    Tire BRtire = new Tire("뒤오른쪽",4);
    
    int run(){
        System.out.println("Car is run");
        if(FLtire.roll()==false){stop(); return 1;}
        if(FRtire.roll()==false){stop(); return 2;}
        if(BLtire.roll()==false){stop(); return 3;}
        if(BRtire.roll()==false){stop(); return 4;}
            return 0;
    }
    
    void stop(){
        System.out.println("Car is stop");
    }
}

 

CarTest

public class CarTest{
    public static void main(String[] args){
        Car car = new Car();
        
        for(int i=0;i<5;i++){
            int problemLocation = car.run();
            
            switch(problemLocation){
                case 1:
                    System.out.println("앞왼쪽 HankookTire로 교체");
                    car.FLtire = new HankookTire("앞왼쪽",15);
                    break;
                case 2:
                    System.out.println("앞오른쪽 KumhoTire로 교체");
                    car.FRtire = new KumhoTire("앞오른쪽",13);
                    break;
                case 3:
                    System.out.println("뒤왼쪽 HankookTire로 교체");
                    car.BLtire = new KumhoTire("뒤왼쪽",14);
                    break;
                case 4:
                    System.out.println("뒤오른쪽 KumhoTire로 교체");
                    car.BRtire = new KumhoTire("뒤오른쪽",11);
                    break;
            }
            System.out.println("---------------------------------------------------");
        }
    }
}

 

CarTest실행결과

 

매개변수의 다형성 예제

public class Vehicle{
    void run(){
        System.out.println("탈 것으로 달립니다.");
    }
}
public class Driver{
    void drive(Vehicle vehicle){
        vehicle.run();
    }
}
public class DriverTest{
    public static void main(String[] args){
        Driver driver = new Driver();
        Vehicle vehicle = new Vehicle();
        driver.drive(vehicle);
    }
}

DriverTest 실행결과

 

여기서 Driver의 메소드 drive의 매개변수로

Vehicle의 자식 클래스들도 들어올 수 있음

Vehicle의 자식 Bus

public class Bus extends Vehicle{
    @Override
    void run(){
        System.out.println("Bus를 타고 달립니다.");
    }
}

 

Vehicle의 자식 Taxi

public class Taxi extends Vehicle{
    @Override
    void run(){
        System.out.println("Taxi를 타고 달립니다.");
    }
}

 

Bus 객체와 Taxi 객체를 받는 Driver클래스의 메소드 drive

Driver클래스는 이전과 동일

public class DriverTest{
    public static void main(String[] args){
        Driver driver = new Driver();
        Vehicle vehicle = new Vehicle();
        Bus bus = new Bus();
        Taxi taxi = new Taxi();
        driver.drive(bus);
        driver.drive(taxi);
    }
}

DriverTest 실행 결과

강제 타입 변환

부모 타입을 자식 타입으로 변환하는 것

모든 경우 가능한 것이 아님

자식 타입에서 부모 타입으로 변환된 객체만 가능

class A{}

class B extends A{}

class C extends B{}

public class Test{
    public static void main(String[] args){
        A a = new A();
        B b = new B();
        C c = new C();
        
        B b1 = c;//부모타입으로 자동 타입 변환
        C c1 = (C)b1;//자식타입으로 강제 타입 변환
        
        //C c2 = b1;//ERROR 타입을 명시적으로 해줘야함
        
        //B b2 = a; ERROR
    }
}

 

자동 타입 변환하면 부모에 선언된 필드와 메소드만 사용가능한데

강제 타입 변환한 다음 다시 자식의 필드와 메소드 사용 가능

 

public class Parent{
    String field1;
    void method1(){System.out.println("Parent method1");}
    void method2(){System.out.println("Parent method2");}
}
public class Child extends Parent{
    String field2;
    @Override
    void method2(){System.out.println("Child method2");}
    void method3(){System.out.println("Child method1");}
}
public class Test{
    public static void main(String[] args){
        Parent parent = new Child();
        parent.field1 = "xx";
        parent.method1();
        parent.method2();
        //parent.field2; ERROR
        //parent.method3(); ERROR
        
        Child child = (Child)parent;
        child.field1 = "asdf";
        child.field2 = "xxx";
        child.method2();
        child.method3();
    }
}

 

Test 실행결과

실행결과에서 2번째 줄에 있는

Childe method2가 나오는 이유는

method2가 Child 클래스에서 재정의 되었기 때문

 

Child에서 method2를 재정의 하지 않았을 때

 

객체 타입 확인

부모 변수가 참조하는 객체가

부모객체인지 자식객체인지 확인 하는법

instanceof 연산자 이용

boolean result  = 좌항(객체) intanceof 우항(타입)

우항의 타입으로 객체가 생성되었다면 ture 반환

주로 매개값이 어떤 객체인지 확인할 때 쓰임

class Parent{}

class Child extends Parent{}

public class Test{
    public static void main(String[] args){
        Parent p1 = new Parent();
        Child c1 = new Child();
        Parent p2 = c1;
        
        instanceOf(p1);
        instanceOf(p2);
        Child c2 = (Child)p2;
        instanceOf(c2);
        p2 = p1;
        instanceOf(p2);
        
    }
    static void instanceOf(Parent p){
        if(p instanceof Child){
            System.out.println("Child instance");
        }
        else{
            System.out.println("Not Child instance");
        }
    }
}

Test 실행결과

'프로그래밍 > Java' 카테고리의 다른 글

인터페이스  (0) 2019.12.04
추상 클래스  (0) 2019.12.04
상속  (0) 2019.12.03
final필드와 상수  (0) 2019.12.03
싱글톤  (0) 2019.12.03