[Java Basic] ch5.자바의 다형성
다형성
여러가지 형태를 가질 수 있는 능력
다형성의 특징
- 부모 참조변수에 부모 인스턴스
Tv tv = new Tv();
- Tv 클래스의 것만 사용 가능
- 부모 참조변수에 자식 인스턴스
Tv captionTv = new CaptionTv();
- Tv 클래스의 것만 사용 가능
- 부모의 것만 사용 가능
- 자식 참조변수에 자식 인스턴스
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();
}
}
참조변수의 형변환
- 업-캐스팅
- 자식 타입의 참조변수를 부모 타입의 참조변수로 형변환 할 때는 생략 가능
- 다운-캐스팅
- 부모 타입의 참조변수를 자식 타입의 참조변수로 형변환 할 때는 생략 불가능
// 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(); // 이건 에러가 아님
}
}
- 부모 참조변수의 자식 인스턴스는 형변환을 해주면 사용 가능.
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(); // 형변환 해주면 사용 가능 } }
- 부모 참조변수의 부모 인스턴스는 자식으로 형변환을 해도 사용 불가능.
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 발생 } }
- 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);
}
}
댓글남기기