article thumbnail image
Published 2022. 9. 17. 17:34

다형성에 대한 개념들을 정리해보려고 한다.


주요학습내용
  • 다형성
  • 참조변수의 형변환
  • instanceof연산자

 

다형성

다형성(polymorphism)
조상 타입 참조 변수로 자손 타입 객체를 다루는 것

class Tv {
	boolean power;
    int channel;
    
    void power() {...}
    void channelUp() {...}
    void channelDown(){...}
}

class SmartTv expends Tv {
	String text; 
    soid caption() {...}
}


SmartTv s = new SmartTv(); //ok
Tv t = new SmartTv(); //조상 타입변수로 자손 타입 객체를 다루고 있음, 타입 불일치 ok
SmartTv p = new Tv(); //자손타입 변수로 조상타입 객체를 다루는것은 불가능!!

참조변수는 정수(객체주소)를 저장하고 있는 변수
대입하면 오른쪽 변수의 값이 왼쪽 변수에 저장될 뿐이다.


참조변수의 타입을 객체를 조종하는 리모콘
객체의 타입을 리모콘으로 조종할 수 있는 객체로 생각하면 편하다.

참조변수의 멤버 수에 따라 참조변수로 사용할 수 있는 멤버의 갯수가 달라진다

리모콘의 버튼의 수가 다루는 객체의 멤버 수보다 적을 수는 있으나
버튼의 수가 더 많으면 오류가 발생한다

자세히 말하면 실제 참조하고 있는 인스턴스의 멤버를 기준으로 참조 변수의 타입의 멤버가 실제 인스턴스의 멤버 수보다 작은 것은 실제 사용할 수 있는 기능을 줄이는 것이기에 허용되지만, 그 반대의 경우는 참조하고 있는 인스턴스에 실제로 구현된 기능이 없어 사용이 불가하기 때문

따라서 자손타입 변수로 조상타입 객체를 다루는 것은 불가능하다.

위 예시에서
s변수의 경우 7개의 멤버를 가진 객체를 7개 모두 쓸 수 있음
t 변수의 경우 7개의 멤버를 가지고 있어도 쓸 수 있는건 5개


참조변수의 형변환

참조변수의 형변환이란
사용할 수 있는 멤버의 개수를 조절하는 것이다(주솟값이나, 값 자체가 달라지는 것이 아니고 오로지 멤버의 수만!!)

HOW? 리모콘 변경(객체는 일치) 가리키는 값만 변환
새로운 참조변수를 만들고 거기다가 값만 넣어줌


타입 변환을 위해서는 다음의 세 가지 조건을 충족해야 한다.

1. 조상-자손 관계에서만 타입 변환이 가능
2. 하위 클래스 타입에서 상위 클래스 타입으로의 타입 변환(업캐스팅)은 형변환 연산자(괄호)를 생략할 수 있다.
3. 상위 클래스에서 하위 클래스 타입으로 변환(다운캐스팅)은 형변환 연산자(괄호)를 반드시 명시해야한다.

class Car {}
class FireEngine extends Car {}
class Ambulance extends Car {}

FireEngine f = new FireEngine(); //인스턴스 생성

Car c = (Car)f; //OK. FireEngine 타입이었던 f를 조상인 Car타입으로 형변환(생략가능)
FireEngine f2 = (FireEngine)c; // OK. Car 타입인 c를 자손 타입인 FireEngine으로 형변환(생략불가)
Ambulance a = (Ambulance)f; //에러. 상속관계가 아닌 클라스 간의 형변환 불가

형변환 과정을 좀더 구체적으로 생각해보면

먼저

Car c = (Car)f; //OK. FireEngine 타입이었던 f를 조상인 Car타입으로 형변환(생략가능)

인스턴스 FireEngine의 주솟값을 가르키는 참조변수f 리모콘을 참조변수c리모콘으로 바꾸는 과정

참조변수 c에 FireEngine인스턴스의 주솟값이 들어가며 c의 타입인 Car가 다루는 멤버 수는 4개이므로
FireEngine 인스턴스의 멤버 5개중에서 4개의 멤버만 다룰 수 있게 된다.
즉 리모컨의 버튼이 5개에서 4개로 바뀐다.

이때는 형변환 구조(Car)를 생략할 수 있다.
버튼의 수가 적어지므로 실행 시 에러가 나는 경우의 수가 없고 안전하기 때문이다.

FireEngine f2 = (FireEngine)c; // OK. Car 타입인 c를 자손 타입인 FireEngine으로 형변환(생략불가)

인스턴스 FireEngine의 주솟값을 가르키는 참조변수c 리모콘을 참조변수f2 리모콘으로 바꾸는 과정

이때 인스턴스에서 다룰 수 있는 멤버수는 4개에서 5개로 늘어나며
이때는 인스턴스 멤버의 수보다 다룰 수 있는 멤버 수가 많이지는 경우가 생기므로
문법적으로 (compile 에러)는 문제없지만 실행중 실행이 안되는 경우가 많다.

따라서 형변환을 생략하지 않고 꼭 써주어야 한다.

이렇게 참조변수의 형변환을 리모콘을 변경하는 과정이라고 생각하면 직관적으로 이해하기 쉽다.


instanceof 연산자

참조변수의 형변환 가능여부 확엔에 사용되는 연산자.boolean 타입 반환.
형변환 전에는 반드시 instanceof로 형변환이 가능한지 확인해야 한다.
만약 참조변수가 null인 경우에는 false를 반환한다.

참조_변수 instanceof 타입

//출력값 true/false


소스 코드가 길어지는 등 일일이 생성 객체의 타입을 확인하기가 어려운 상황에서 instanceof 연산자는 형변환 여부를 확인하여 에러를 최소화해준다.

다형성의 활용 예제
public class Practice_polymorphism {
    public static void main (String[] args){
        Customer customer = new Customer();
        //customer.buycoffee(new Americano());는 아래와동일
        //Customer customer = new Americano(); (포함관계)
        //  customer.buycoffee(Americano);
        customer.buyCoffee(new Americano());
        customer.buyCoffee(new CaffeLatte());

        System.out.println("현재 잔액은" + customer.money +"원 입니다.");
    }
}
class Coffee { //커피의 가격 입력받는 메서드를 포함한 커피클라스
    int price;

    public Coffee(int price){
        this.price = price;
    }
}
//이를 상속받는 아메리카노,카페라테 클라스
class Americano extends Coffee{
    public Americano(){
        super(4000); //상위클래스인 coffee의 생성자 호출
    }
    public String toString() {return  "아메리카노";}; //Object클래스 toString()메서드 오버라이딩
};
class CaffeLatte extends Coffee {
    CaffeLatte() {
        super(5000);
    }

    public String toString() {
        return "카페라떼";
    }

    ;
};

class Customer{ //구매자는 5만원 가지고 ㅣㅇㅆ다.
    int money = 50000;
    void buyCoffee(Coffee coffee){
        //물건 가격보다 돈이 없는경우
        if(money<coffee.price){
            System.out.println("잔액이 부족합니다");
            return;
        }
        money = money -coffee.price;
        System.out.println(coffee + "를 구입힜습니다.");
    }
}

 

학습 후 느낀점

HOW?와 WHY?를 자꾸 생각해보기
그림을 그려 구조를 시각화하기

객체지향은 눈에 보이지 않기에 다소 애매한 개념이다
참조변수에 어떤 과정으로 객체의 주소가 저장되는지 그림으로 구조를 그려가며 시각화했더니
좀 더 직관적으로 들어왔고 이해가 편했다
또 이번개념은 특히 유어클라스의 자료뿐만 아니라 유튜브의 영상강의를 많이 참고했다
아래는 가장 많이 도움이 되었던 남궁민의 정석코딩 - 자바의 정석 강의이다.
https://www.youtube.com/watch?v=XP8zpt-yFZs

'Java' 카테고리의 다른 글

Java - 람다와 메서드 참조  (0) 2022.09.18
Java-삼항연산자  (0) 2022.09.17
Java - 클라스와 객체,필드와 메서드  (5) 2022.09.17
Java - 스레드의 생성과 실행  (0) 2022.09.17
Java 기초  (0) 2022.09.06
복사했습니다!