본문 바로가기

Java 기본 문법 - 참조 서적 [이것이 자바다 - 한빛미디어]/5. 상속, 다형성

4. Java 자바 - 타입 변환과 다형성

다형성 

같은 타입이지만 실행 결과가 다양한 객체를 이용할 수 있는 성질

하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 해준다.

 

다형성을 위해 자바는 부모 클래스로 타입 변환을 허용한다.

 

부모 타입에 모든 자식 객체가 대입될 수 있다. (부모 타입의 규격화)

이것을 이용하면 객체는 부품화가 가능하다.

 

ex) 타이어 클래스 타입을 적용했다면 이 클래스를 상속한 실제 타이어들은 어떤 것이든

상관 없이 장착(대입) 가능하다.

 

 

 

자동차는 타이어 타입으로 Hankook 타이어와 Kumho 타이어를 사용하지만,

각 타이어의 성능은 다르게 나온다. <다형성>

 

위 그림은 아래 코드처럼 표현된다.

 

public class Car {
    Tire t1 = new HankookTire();  // 자식 타입 객체 대입
    Tire t2 = new KumhoTire();
}

 

타입 변환

 

데이터 타입을 다른 데이터 타입으로 변환하는 행위

 

클래스 타입도 기본 데이터 타입 변환과 마찬가지로 타입 변환이 있다. (기본 데이터 타입 변환)

 

클래스 타입 변환은 상속 관계에 있는 클래스 사이에서 발생한다.

자식 타입은 부모 타입으로 자동 타입 변환이 가능하다!! ( 자식 < 부모)

 

위의 그림에서 HankookTire와 KumhoTire 는 Tire 를 상속했기 때문에, Tire 변수에 대입할 수 있다.

 


 

자동 타입 변환 (Promotion)

 

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

 

자동 타입 변환은 아래와 같은 조건에서 일어난다.

 

 

부모 클래스 타입으로 자동 타입 변환

 

자동 타입 변환 개념은

자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다.

 

ex) 고양이는 동물의 특징과 기능을 상속 받았다. 따라서 "고양이는 동물이다." 가 성립된다.

 

Animal 과 Cat 클래스가 아래와 같이 상속 관계에 있을 때

 

Animal 클래스와 Cat 클래스 상속 관계

 

 

Cat 클래스로부터 Cat 객체를 생성하고, 이것을 Animal 변수에 대입하면 자동 타입 변환이 일어난다.

 

Cat cat = new Cat();
Animal animal = cat;    // Animal animal = new Cat(); 도 가능하다.

 

위의 코드의 메모리 상태는 아래와 같다. cat 과 animal 변수는 타입만 다를 뿐, (Cat, Animal)

동일한 Cat 객체를 참조한다.

 

Cat 타입 변수 cat = Cat 객체 참조 주소 값

Animal 타입 변수 animal = Cat 객체 참조 주소 값

 

 

동일한 Cat 객체를 참조한다.

즉, Animal 타입 변수 amimal 은 Cat 객체를 참조할 수 있다. <자동 타입 변환>

왜냐하면, Cat 객체는 Animal 객체를 상속 받았기 때문이다. (상속 관계이어야 한다.)

 

animal 변수가 Animal 타입이므로

당연히 부모인 Animal 객체를 참조하는 것이 맞다라고 생각할 수 있지만, 그렇지 않다!!

 

cat, animal 변수를 == 연산해보면, true 가 리턴되는데,

참조 변수의 == 연산은 참조 주소값이 같으면 true 를 반환하므로,

두 변수가 동일한 객체를 참조하고 있다.

 

cat == animal;  // true

 

바로 위의 부모가 아니더라도, 상속 계층에서 상위 타입이라면, 자동 타입 변환이 일어날 수 있다.

 

 

ex)

 

 

D 객체는 B, A 타입으로 자동 타입 변환이 될 수 있고,

E 객체는 C, A 타입으로 자동 타입 변환 될 수 있다.

 

하지만, D 객체는 C 타입으로 변환될 수 없고, E 객체는 B 타입으로 변환될 수 없다.

<상속 관계가 아니기 때문!!>

 

ex) PromotionExample.java

class A { }

Class B extends A { }
Class C extends A { }

class D extends B { }
class E extends C { }

public class PromotionExample {
    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 = d;
        C c1 = e;
        
        // B b3 = e;  컴파일 에러 (상속 관계가 아니다.)
        // C c2 = d;  컴파일 에러 (상속 관계가 아니다.)
    }
}

 

자동 타입 변환 후 주의할 점!!

 

부모 타입으로 자동 타입 변환된 변수는 부모 클래스에 선언된 필드와 메소드만 접근 가능하다.

 

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

 

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

 

예외) 메소드가 자식 클래스에서 오버라이딩되었다면, 자식 클래스의 메소드가 대신 호출된다.

(다형성과 관련)

오버라이딩되었다면, 자식 클래스의 메소드에 접근 가능하다.

 

ex) 

 

자동 타입 변환 시 부모 클래스 멤버만 접근 가능하다. (오버라이딩 예외)

 

child 객체는 method3( ) 메소드를 가지고 있지만,

Parent 타입으로 변환된 이후에는 method3( ) 을 호출할 수 없다.

 

하지만 method2( ) 메소드는 부모와 자식 모두가 가지고 있다.

 

이렇게 오버라이딩된 메소드 (method2( )) 는 타입 변환 이후에도 자식 메소드가 호출된다.

 

 

Parent.java

public class Parent {
    
    //메소드
    public void method1() {
        System.out.println("Parent - method1()");
    }
    
    public void method2() {
        System.out.println("Parent - method2()");
    }
}

 

Child.java

public class Child extends Parent {
    @Override
    public void method2() {   // 부모의 method2 재정의됨
        System.out.println("Child - method2()");
    }
    
    public void method3() {
        System.out.println("Child - method3()");
    }
}

 

ChildExample.java

public class ChildExample {
    public static void main(String[] args) {
        Child child = new Child();
        
        Parent parent = child;    // 자동 타입 변환
        
        parent.method1();
        parent.method2();   // 재정의된 메소드 호출 (자식 메소드)
        //parent.method3();  // 호출 불가능
    }
}