[Java] 다형성

박채은·2022년 11월 8일
0

Java

목록 보기
16/30

학습 목표

  • 자바 객체지향 프로그래밍에서 다형성이 가지는 의미와 장점을 이해할 수 있다.
  • 참조변수의 타입 변환에 대한 내용을 이해하고, 업캐스팅과 다운캐스팅의 차이를 설명할 수 있다.
  • instanceof 연산자를 언제 어떻게 활용할 수 있는 지 이해하고 설명할 수 있다.

다형성

  • poly(여러 개) + morphism(형태/실체)
  • 하나의 객체가 여러 가지 형태를 가질 수 있는 성질

다형성은 크게 2가지로 나눌 수 있다.

  1. 한 타입의 참조 변수를 통해 여러 타입의 객체를 참조하는 것
  2. 오버로딩, 오버라이딩을 통해서 메서드를 재사용/덮어쓰기 하는 것

예시)

class Friend {
	String name;
    public void friendInfo() {
        System.out.println("나는 당신의 친구입니다.");
    }
}
class GirlFriend extends Friend {
	int height;
    public void friendInfo() {
        System.out.println("나는 당신의 여자친구입니다.");
    }
}

public class FriendTest {
    public static void main(String[] args) {
    	// 객체 타입과 참조변수 타입의 일치
        Friend friend = new Friend(); 
        // (가능⭕) 상위 클래스의 타입으로 하위 클래스의 객체를 참조
        Friend girlfriend1 = new GirlFriend(); 
        // (불가능❌) 하위 클래스의 타입으로 상위 클래스의 객체를 참조
        GirlFriend girlfriend2 = new Friend();
		
        friend.friendInfo();
        girlfriend.friendInfo(); // 오버라이딩된 메소드가 호출
        
        // GirlFriend 클래스의 height 변수에 접근 불가
        girlfriend.height = 160;
    }
}

// 출력값
나는 당신의 친구입니다.
나는 당신의 여자친구입니다.

상위 클래스 타입의 참조 변수로 하위 클래스의 객체를 참조 가능
하위 클래스 타입의 참조 변수로 상위 클래스의 객체를 참조할 수 없다!

참조 변수가 사용할 수 있는 멤버 = 상위 클래스의 멤버

Friend 타입으로 GirlFriend 인스턴스를 참조하면, Friend 클래스의 멤버만 사용할 수 있다.
GirlFriend 클래스의 멤버는 사용하지 못하므로, 오히려 사용할 수 있는 멤버는 줄어들게 된다.

왜 하위 클래스의 타입으로 상위 클래스 객체를 참조하는 것은 불가능할까?
💁‍♀️ 객체(상위 클래스)의 멤버 개수보다, 참조 변수(하위 클래스)의 멤버 개수가 많기 때문이다.

(객체의 멤버 수 > 참조 변수의 멤버 수): 실제 사용할 수 있는 기능을 사용하지 않는 것이기 때문에 문제가 없음
(객체의 멤버 수 < 참조 변수의 멤버 수): 사용할 수 있는 기능이 구현되지 않은 것이므로 문제가 발생한다.


참조 변수의 타입 변환(캐스팅)

조건

  1. 서로 상속관계에 있는 상위 클래스-하위 클래스 사이에만 타입 변환이 가능하다.
  2. 하위 클래스 타입에서 상위 클래스 타입으로의 타입 변환(업캐스팅)은 괄호를 생략할 수 있다.
  3. 반대로 상위 클래스에서 하위 클래스 타입으로 변환(다운캐스팅)은 괄호를 반드시 명시해야 한다.
public class VehicleTest {
    public static void main(String[] args) {
        Car car = new Car();
        // 업 캐스팅
        Vehicle vehicle = car;
        // 다운 캐스팅(괄호 생략 불가능)
        Car car2 = (Car) vehicle;
        // 상속관계가 아니므로 타입 변환 불가 -> 에러발생
        MotorBike motorBike = (MotorBike) car; 
    }
}

class Vehicle {}
class Car extends Vehicle {}
  • 캐스팅을 통해서 사용할 수 있는 멤버의 개수를 조절할 수 있다.

instanceof 연산자

  • 캐스팅이 가능한지 확인할 때 사용
    • 좌항 인스턴스의 클래스가 우항 클래스와 같거나 하위 클래스라면 true 반환(아니면 false)
 참조_변수 instanceof 타입
public class InstanceOfExample {
    public static void main(String[] args) {
        Animal animal = new Animal();
        System.out.println(animal instanceof Object); //true
        System.out.println(animal instanceof Animal); //true
        System.out.println(animal instanceof Bat); //false

        Animal cat = new Cat();
        System.out.println(cat instanceof Object); //true
        System.out.println(cat instanceof Animal); //true
        System.out.println(cat instanceof Cat); //true
        System.out.println(cat instanceof Bat); //false
    }
}

class Animal {};
class Bat extends Animal{};
class Cat extends Animal{};

궁금증-해결

나의 궁금증

분명 "하위 클래스 타입의 참조 변수로 상위 클래스의 객체를 참조할 수 없다"라고 배웠는데 어떻게 다운 캐스팅이 가능할까?

해결

다운 캐스팅은 단순히 하위 클래스 타입의 참조 변수로 상위 클래스의 객체를 참조하는 것이 아니다.
다운 캐스팅은 업 캐스팅이 선행된 후에, 다시 원래 타입으로 돌아가는 것을 말한다.(원상 복구)

따라서 그냥 하위 클래스가 상위 클래스 객체를 참조하는 것은 불가능하지만, 업 캐스팅 후에 다운 캐스팅을 하는 것은 가능하다.
그리고 그때 instanceof 연산자가 사용된다.

  1. 하위 클래스의 타입으로 상위 클래스 타입의 객체를 참조를 한 경우
    Casting 'friend' to 'GirlFriend' will produce 'ClassCastException' for any non-null value 발생
public class Main {

    public static void main(String[] args) {
        // (업 캐스팅) 상위 클래스의 타입으로 하위 클래스 타입의 객체를 참조
        Friend girlfriend = new GirlFriend();
        // (다운 캐스팅 X) 하위 클래스의 타입으로 상위 클래스 타입의 객체를 참조
        // Exception 발생!
        GirlFriend friend1 = (GirlFriend) friend; 
    }
}

코드는 비슷한 형태이지만, 다운 캐스팅의 경우에는 exception이나 오류가 발생하지 않는다.

  1. 다운 캐스팅인 경우
public class Main {
    public static void main(String[] args) {     
        // 상위 클래스의 타입으로 하위 클래스 타입의 객체를 참조(= 업 캐스팅)
        Friend girlfriend = new GirlFriend();
        // 다운 캐스팅
        GirlFriend friend = (GirlFriend) girlfriend;
    }
}

참고 - 다운 캐스팅과 instanceof

0개의 댓글