좌충우돌 개발공부

TIL(20240512) JAVA : 다형성


💡 다형성

  • 조상 타입 참조변수로 자손 타입 객체를 다루는 것
class Tv () { // 부모클래스
}

class SmartTv extends Tv () { // 자식클래스
}
Tv tv = new SmartTv() // ⭕ 부모클래스 참조변수로 자식클래스 인스턴스를 생성

SmartTv smartTv = new Tv() // ❌ 자식클래스 참조변수로 부모클래스 인스턴스 생성 불가 

❌ 자손 타입의 참조변수로 조상 타입의 객체를 가르킬 수 없다.

  • 그 이유는? 부모클래스(Tv)의 멤버변수를 자식클래스(SmartTv)가 상속받게 되는데 예를 들어 부모클래스의 멤버변수가 3개라면 자식클래스가 가지고 있던 멤버변수 2개 + 부모클래스 멤버변수 3개를 합쳐서 자식클래스가 가지게 되는 멤버변수는 5개이다. 그런데 자식클래스의 참조변수로 부모클래스 인스턴스를 생성하려고 하면 자식클래스 참조변수가 가지고 있는 멤버변수는 5개인데 부모클래스가 가지고 있는 멤버변수가 3개 뿐이기 때문에 멤버변수 2개를 허용되지 않기에 에러가 발생한다.
  • 참조변수의 타입과 인스턴스의 타입이 반드시 일치하지 않아도 되는 것이 “다형성”이다.

❓ 참조변수가 부모타입일 때와 자손타입일 때의 차이는 무엇인가

  • 참조변수로 사용할 수 있는 갯수가 달라진다. 부모클래스(Tv)의 멤버갯수가 3개, 자식클래스(SmartTv)가 가지고 있었던 멤버변수 2개와 부모클래스의 멤버변수를 포함하여 총 5개를 가지고 있다면
Tv tv = new SmartTv() // 멤버변수 3개만 사용가능
SmartTv smartTv = new SmarTv() // 멤버변수 5개 사용가능

💡 참조변수의 형변환

  • 기본형의 형변환은 “값” 바뀐다.
  • 참조변수의 형변환은 주소값이나 객체가 달라지는 것이 아니라 사용할 수 있는 멤버의 갯수를 조절할 수 있다.
  • 부모,자식 관계의 참조변수는 서로 형변환 가능
  • 형제관계는 형변환 불가

💡 instanceof 연산자

  • 참조변수의 형변환 가능여부 확인에 사용, 가능하면 true 반환
  • 형변환 전에 반드시 instanceof로 확인해야함
// instanceof 연산자 사용법
void doWork(Car c) {
    if (c instanceof FireEngine) {// 형변환 가능한지 확인 
        FireEngine fe = (FireEngine) c; // 형변환
        fe.water();
    }
}

💡 매개변수의 다형성

  • 장점: 다형적 매개변수, 하나의 배열로 여러종류 객체다루기
  • 참조형 매개변수는 메서드 호출시, 자신과 같은 타입 또는 자손타입의 인스턴스를 넘겨줄 수 있다.
class Product {
    int price;
    int point;

    Product (int price) {
        this.price = price;
        point = (int) (price/10.0); // 가격의 10%로 적립
    }

}
class Tv extends Product {
     Tv() { super(100); } // 생성자
    void String toString() {
        return "TV";
    }
}
class Computer extends Product {
    Computer() { super(200); } // 생성자
    void String toString() {
        return "Computer";
    }
}
class Audio extends Product {
    Audio() { super(50); } // 생성자
    void String toString() {
        return "Audio";
    }
}

class Buyer {
    int money = 1000;
    int point = 0;

void buy(Product p) { // Tv, Computer, Audio
    if (money < p.price) {
        System.out.println("잔액이 부족합니다.")
        return; 
    }
    money -= p.price;
    bonusPoint += p.point;
    System.out.println(p + "을 구입하셨습니다.")
    System.out.println(p.toString() + "을 구입하셨습니다.") // 출력시 위와 동일
}
}

class Main{

public static void main(String args[]) {

Buyer buyer = new Buyer();

// 아래 b.buy(new Tv())와 같음.
Product p = new Tv(); 
b.buy(p); 

// 참조변수를 이용하여 사용할 순 없음
b.buy(new Tv()); 

    }
}

💡 여러 종류의 객체를 배열로 다루기

  • 조상타읍의 배열에 자손들의 객체를 담을 수 있다.
class Buyer {
    int money = 1000;
    int point = 0;
    Product[] cart = new Product[10]; // 구입한 제품을 저장하기 위한 배열
    int i = 0; // Product 배열에 사용될 카운터

void buy(Product p) { // Tv, Computer, Audio
    if (money < p.price) {
        System.out.println("잔액이 부족합니다.")
        return; 
    }
    money -= p.price;
    bonusPoint += p.point;
    cart[i++] = p; // Product[] 배열에 저장됨
    System.out.println(p + "을 구입하셨습니다.")
}

void summary () { // 구입한 물품을 요약해서 보여주기
    int sum = 0; // 가격 합계
    String itemList = ""; // 구입한 물품목록
for (int i=0; i < cart.length; i++) {
    if (cart[i] == null ) break;
    sum += cart[i].price;
    itemList += cart[i] + ", ";
        }
System.out.println("구입하신 총 금액은 "+ sum +" 입니다.")
System.out.println("구입하신 총 물품은 "+ itemList + "입니다.")
    }

}
// 반복문을 이용해서 구입한 물품의 총 가격과 목록을 만들기

class Main{

public static void main(String args[]) {

Buyer buyer = new Buyer();

// 아래 b.buy(new Tv())와 같음.
Product p = new Tv(); 
b.buy(p); 

// 참조변수를 이용하여 사용할 순 없음
b.buy(new Tv()); 
b.summary();

    }
}