다형성

여러가지 형태를 가질 수 있는 능력

다형성의 특징

  1. 부모 참조변수에 부모 인스턴스 Tv tv = new Tv();
    • Tv 클래스의 것만 사용 가능
  2. 부모 참조변수에 자식 인스턴스 Tv captionTv = new CaptionTv();
    • Tv 클래스의 것만 사용 가능
    • 부모의 것만 사용 가능
  3. 자식 참조변수에 자식 인스턴스 CaptionTv realCaptionTv = new CaptionTv();
    • CaptionTv 클래스의 것도 사용 가능
public class Tv {
    private boolean power;
    private int channel;

    public void power() {
        this.power = !this.power;
    }

    public void channelUp() {
        this.channel++;
    }

    public void channelDown() {
        this.channel--;
    }

    public boolean isPower() {
        return power;
    }

    public void setPower(boolean power) {
        this.power = power;
    }

    public int getChannel() {
        return channel;
    }

    public void setChannel(int channel) {
        this.channel = channel;
    }
}
public class CaptionTv extends Tv{
    private String text;

    public void caption(){
        System.out.println("캡션 출력 : " + text);
    }

    public String getText() {
        return text;
    }

    public void setText(String text) {
        this.text = text;
    }
}

public class Client {

    public static void main(String[] args) {
        Tv tv = new Tv();
        Tv captionTv = new CaptionTv();
        CaptionTv realCaptionTv = new CaptionTv();

        tv.power();
        tv.channelUp();
        System.out.println("tv power : " + tv.isPower());
        System.out.println("tv channel : " + tv.getChannel());

        captionTv.power();
        captionTv.channelUp();
        System.out.println("captionTv power : " + captionTv.isPower());
        System.out.println("captionTv channel : " + captionTv.getChannel());

        realCaptionTv.power();
        realCaptionTv.channelUp();
        System.out.println("realCaptionTv power : " + realCaptionTv.isPower());
        System.out.println("realCaptionTv channel : " + realCaptionTv.getChannel());
        realCaptionTv.setText("Hello World");
        realCaptionTv.caption();
    }
}

참조변수의 형변환

  1. 업-캐스팅
    • 자식 타입의 참조변수를 부모 타입의 참조변수로 형변환 할 때는 생략 가능
  2. 다운-캐스팅
    • 부모 타입의 참조변수를 자식 타입의 참조변수로 형변환 할 때는 생략 불가능
// Car.java
public class Car {
    String color;
    String door;

    public void drive(){
        System.out.println("drive");
    }
}
// FireEngine.java
public class FireEngine extends Car{
    public void water(){
        System.out.println("water");
    }
}
// Ambulance.java
public class Ambulance extends Car{
    public void siren(){
        System.out.println("siren");
    }
}
public class Client {
    public static void main(String[] args) {
        Car car = null;
        FireEngine fe = new FireEngine();
        FireEngine fe2 = null;

        // 업 캐스팅
        car = fe; // 업 캐스팅 car = (Car) fe; 
        car.water(); // 이건 에러
      
        // 다운 캐스팅
        fe2 = (FireEngine) car; 
        fe2.water(); // 이건 에러가 아님
    }
}
  1. 부모 참조변수의 자식 인스턴스는 형변환을 해주면 사용 가능.
    public class Client {
     public static void main(String[] args) {
         Car embulance = new Embulance();
         Car fireEngine = new FireEngine();
    
         embulance.drive();
         fireEngine.drive();
    
         ((Embulance) embulance).siren(); // 형변환 해주면 사용 가능
         ((FireEngine) fireEngine).water(); // 형변환 해주면 사용 가능
     }
    }
    
  2. 부모 참조변수의 부모 인스턴스는 자식으로 형변환을 해도 사용 불가능.
    public class Client {
     public static void main(String[] args) {
         Car car = new Car();
         Car car2 = null;
         FireEngine fireEngine = null;
         fireEngine = (FireEngine) car; // compile error는 아니지만 runtime error 발생
     }
    }
    
  3. 4번의 경우 때문에 형변환을 하기 전에 instanceof 연산자를 통해 확인을 해야한다.
    public class Client {
     public static void main(String[] args) {
         Car car = new FireEngine();
         FireEngine fireEngine = null;
            
         if (car instanceof FireEngine){
             fireEngine = (FireEngine) car;
             fireEngine.drive();
         }else{
             fireEngine = new FireEngine();
             System.out.println("fireEngine2 is not FireEngine instance");
         }
     }
    }
    

부모의 멤버와 자식의 멤버

public class Client {
    public static void main(String[] args) {
        Parent p = new Child();
        Child c = new Child();

        System.out.println(" Parent :  " + p.x ); //100
        System.out.println(" Child : " + c.x ); //200
        System.out.println("------------------------------");
        p.method(); // "Child Method"
        c.method(); // "Child Method"

    }
}

// Child.java
public class Child extends Parent{
  int x = 200;

  void method(){
    System.out.println("Child Method");
  }
}

// Parent.java
public class Parent {
  int x = 100;
  void method(){
    System.out.println("Parent Method");
  }
}


다형성을 활용한 코드

Product

public class Product {
    private int price;
    private int bonusPoint;

    public Product(int price) {
        this.price = price;
        this.bonusPoint = (int) (price / 10.0);
    }

    public int getPrice() {
        return price;
    }

    public int getBonusPoint() {
        return bonusPoint;
    }
}

// Tv.java
public class Tv extends Product{
  private static final int price = 1_000_000;

  public Tv() {
    super(price);
  }
}

// Computer.java
public class Computer extends Product{
  private static final int price = 500_000;

  public Computer() {
    super(price);
  }
}

ShoppingBasket.java

public class ShoppingBasket {
    private Vector<Product> products = new Vector<>();

    public boolean add(Product product) {
        return products.add(product);
    }

    public boolean remove(Product product) {
        return products.remove(product);
    }

    public void showBasket(){
        System.out.print("장바구니 목록 : ");
        String products = this.products.stream().map(p -> p.getClass().getSimpleName() + " ").collect(Collectors.joining(", "));
        System.out.println(products);
    }

}

Client.java

public class Client {
    private int money = 200_000_000;
    private int bonusPoint = 0;
    private ShoppingBasket shoppingBasket = new ShoppingBasket();

    public void buy(Product product) {
        if (money < product.getPrice()) {
            throw new IllegalArgumentException(" 잔액이 부족합니다. ");
        }

        money -= product.getPrice();
        bonusPoint += product.getBonusPoint();
        System.out.println(product.getClass().getSimpleName() + "을/를 구입하셨습니다.");

        showMoney();
        showPoint();

        shoppingBasket.add(product);
    }

    public void refund(Product product){
        if(shoppingBasket.remove(product)){
            this.money += product.getPrice();
            this.bonusPoint -= product.getBonusPoint();
            System.out.println(product.getClass().getSimpleName() + "을/를 반품하셨습니다.");
            showMoney();
            showPoint();
        }else{
            System.out.println("해당 제품이 장바구니에 없습니다.");
        }
    }

    public void showMoney(){
        System.out.println("잔여 금액 : " + this.money);
    }

    public void showPoint(){
        System.out.println("누적 포인트 : " + this.bonusPoint);
    }

    public static void main(String[] args) {
        Client client = new Client();
        Tv tv = new Tv();
        Computer computer = new Computer();
        client.buy(tv);
        client.buy(computer);
        client.shoppingBasket.showBasket();
        
        client.refund(computer);
        client.refund(tv);
    }
}

추상클래스를 활용한 코드

댓글남기기