-
14. 다형성개발자 수업/Java 2021. 10. 11. 18:10
1. 다형성(polymorphism)
1) 사전적 : 여러 가지 형태를 취할 수 있는 능력
2) 하나의 참조변수로 여러 타입의 객체를 참조할 수 있는 것
즉 조상의 참조변수로 자손타입의 객체를 다룰 수 있는 것
=> 원래의 타입은 유지됨
하나의 코드로 여러 자료형으로 구현되어 실행되는 것
같은 코드로 여러 다른 실행 결과가 나옴
3) 정보은닉, 상속과 더불어 OOP의 가장 큰 특징 중 하나임
4) 다형성을 잘 확용하면 유연하고 확장성 있고, 유지보수가 편리한 프로그램을 만들 수 있음package kr.co.ezenac.polymorphism; // 조상 클래스 public class Player { // 멤버변수 private String name; private int age; private int backNumber; private int speed; // 생성자 public Player(String name, int age, int backNumber, int speed) { super(); this.name = name; this.age = age; this.backNumber = backNumber; this.speed = speed; } // getter() 메서드 제공 public String getName() { return name; } public int getAge() { return age; } public int getBackNumber() { return backNumber; } public int getSpeed() { return speed; } public void showInfo() { System.out.println("이름 : " + this.getName()); System.out.println("나이 : " + this.getAge()); System.out.println("등 번호 : " + this.getBackNumber()); System.out.println("속도 : " + this.getSpeed()); } }
// 자손 클래스 public class Striker extends Player { private int shoot; public Striker(String name, int age, int backNumber, int speed, int shoot) { super(name, age, backNumber, speed); // Player의 생성자 this.shoot = shoot; } public int getShoot() { return this.shoot; } @Override public void showInfo() { super.showInfo(); // Player의 showInfo()를 호출 System.out.println("유효 슈팅 : " + this.getShoot()); } }
public class MidFielder extends Player { private int pass; public MidFielder(String name, int age, int backNumber, int speed, int pass) { super(name, age, backNumber, speed); this.pass = pass; } public int getPass() { return this.pass; } @Override public void showInfo() { super.showInfo(); System.out.println("패스 횟수 : " + this.getPass()); } }
public class Defender extends Player { private int defence; public Defender(String name, int age, int backNumber, int speed, int defence) { super(name, age, backNumber, speed); this.defence = defence; } public int getDefence() { return this.defence; } @Override public void showInfo() { super.showInfo(); System.out.println("방어 횟수 : " + this.getDefence()); } }
public class PlayerTest { public static void main(String[] args) { // 다형성 미적용 코드 Player player = new Player("박지성", 40, 20, 60); player.showInfo(); System.out.println(); // 다형성 적용 코드 (필드의 다형성) // 원래 타입은 유지됨 그래서 Striker 클래스의 getShoot()메서드는 player2참조변수가 접근이 안 됨 Player player2 = new Striker("손흥민", 25, 10, 90, 50); // 상속관계에서 자손클래스에서 오버라이딩을 하게 되면 현재 참조하고 있는 인스턴스의 메서드를 호출함 player2.showInfo(); System.out.println(); Player player3 = new MidFielder("이강인", 18, 18, 90, 120); player3.showInfo(); System.out.println(); Player player4 = new Defender("김영권", 28, 18, 60, 60); player4.showInfo(); } }
2. 다형성으로 인한 형변환(캐스팅)
1) 형변환의 전제 조건 -- 상속, 구현관계에 있는 것만 객체타입 변환이 가능
2) Up-casting : 자손타입에서 조상타입으로 형변환, 형번환 생략가능 (묵시적) ==> 조작 멤버변수가 줄어듦
3) Down-casting
- 조상타입을 자손타입으로 형변환, 형변환 생략불가 (명시적) ==> 조작 멤버변수가 많아짐
- 업캐스팅된 클래스를 다시 원래의 타입으로 형변환
4) instanceof 연산자
- 인스턴스의 형 체크
- 참조변수가 참조하는 인스턴스의 실제 타입을 체크하는데 사용함
- instanceof의 연산결과가 true면 해당 타입으로 형변환이 가능함// 조상클래스 public class Car { String color; int door; public void drive() { System.out.println("차가 달립니다."); } public void stop() { System.out.println("차가 멈춥니다."); } }
// 자손클래스 public class SportsCar extends Car { public void speedUp() { System.out.println("속도를 올립니다."); } }
public class PoliceCar extends Car { public void siren() { System.out.println("사이렌을 울립니다."); } }
public class CarTest { public static void main(String[] args) { Car car = null; SportsCar sportsCar = new SportsCar(); PoliceCar policeCar = new PoliceCar(); sportsCar.speedUp(); car = sportsCar; // 업캐스팅(자손->조상) : 조작할 수 있는 멤버 줄어듦 // car.speedUp(); 불가능 SportsCar sportsCar2 = null; sportsCar2 = (SportsCar)car; // 다운캐스팅(조상->자손) : 조작할 수 있는 멤버 늘어남 sportsCar2.speedUp(); // 서로 관련없는 클래스들 간의 형변환 : 서로 상속관계가 아니기 때문에 형변환이 이루어질 수 없음 // sportsCar = policeCar; 불가능 } }
public class InstanceofTest { public static void main(String[] args) { SportsCar sportsCar = new SportsCar(); if(sportsCar instanceof SportsCar) { System.out.println("SportsCar로 타입변환이 가능합니다."); } if(sportsCar instanceof Car) { System.out.println("Car로 타입변환이 가능합니다."); } if(sportsCar instanceof Object) { System.out.println("Object로 타입변환이 가능합니다."); } } }
public class Parent { int x = 100; /* * 매개변수 타입이 Object라는 것은 어떠한 클래스도 다 받아주겠다는 것 */ public void type(Object obj) { if(obj instanceof Parent) { // 강제 타입캐스팅 Parent parent = (Parent)obj; System.out.println("조상클래스의 멤버 x값 : " + parent.x); } else { System.out.println("Parent 타입의 객체가 아니다. 상속관계에 있지 않은 클래스이다."); } } public void method() { System.out.println("조상메서드 호출"); } }
public class Child extends Parent { int x = 200; @Override public void method() { System.out.println("자손메서드 호출"); } }
public class Car { String color; int door; public void drive() { System.out.println("차가 달립니다."); } public void stop() { System.out.println("차가 멈춥니다."); } }
3. 매개변수의 다형성
1) 참조타입 매개변수는 메서드 호출 시 자신과 같은 타입이거나 또는 자손타입의 주소 즉 인스턴스를 넘겨주도록 함public class Product { int price; // 제품의 가격 int bonusPoint; // 제품 구매 시 제공하는 보너스 점수 public Product(int price) { this.price = price; // 보너스 점수는 제품 가격의 10%를 적립 this.bonusPoint = (int)(price/10.0); } }
public class TV extends Product { public TV() { super(300); } @Override public String toString() { return "TV"; } }
public class Computer extends Product { public Computer() { super(200); } @Override public String toString() { return "Computer"; } }
public class Audio extends Product { public Audio() { super(100); } @Override public String toString() { return "Audio"; } }
public class Buyer { int money = 1000; // 보유금액 int bonusPoint = 0; // 보너스 점수 // public void buy(TV tv) { // // 구매자가 가진 돈보다 제품의 가격이 비싼 경우 // if(this.money < tv.price) { // System.out.println("잔액이 부족하여 물건 구입이 안됩니다."); // return; // } // this.money -= tv.price; // this.bonusPoint += tv.bonusPoint; // System.out.println(tv + "를 구매하셨습니다."); // } // // public void buy(Audio audio) { // // 구매자가 가진 돈보다 제품의 가격이 비싼 경우 // if(this.money < audio.price) { // System.out.println("잔액이 부족하여 물건 구입이 안됩니다."); // return; // } // this.money -= audio.price; // this.bonusPoint += audio.bonusPoint; // System.out.println(audio + "를 구매하셨습니다."); // } // // public void buy(Computer computer) { // // 구매자가 가진 돈보다 제품의 가격이 비싼 경우 // if(this.money < computer.price) { // System.out.println("잔액이 부족하여 물건 구입이 안됩니다."); // return; // } // this.money -= computer.price; // this.bonusPoint += computer.bonusPoint; // System.out.println(computer + "를 구매하셨습니다."); // } /* * 여기서 매개변수 Product 타입이 파라미터 타입에 다형성을 적용 * => Product 타입이거나 그의 자손들은 다 올 수 있다는 것을 의미 (매개변수의 다형성) */ public void buy(Product product) { // 구매자가 가진 돈보다 제품의 가격이 비싼 경우 if(this.money < product.price) { System.out.println("잔액이 부족하여 물건 구입이 안됩니다."); return; } this.money -= product.price; this.bonusPoint += product.bonusPoint; System.out.println(product + "를 구매하셨습니다."); } }
public class PolyArgumentTest { public static void main(String[] args) { Buyer buyer = new Buyer(); buyer.buy(new TV()); System.out.println("현재 남은 돈 : " + buyer.money + "만원 입니다."); System.out.println("현재 보너스 포인트 : " + buyer.bonusPoint + "점 입니다."); buyer.buy(new Audio()); buyer.buy(new Computer()); System.out.println("현재 남은 돈 : " + buyer.money + "만원 입니다."); System.out.println("현재 보너스 포인트 : " + buyer.bonusPoint + "점 입니다."); } }
4. 여러 종류의 객체를 배열로 다루기
1) 조상타입의 배열에는 조상 뿐만 아니라 자손들의 객체도 담을 수 있음// 상품관리 프로그램 public class Product { private int productID; private String description; private String maker; private int price; public Product(int productID, String description, String maker, int price) { super(); this.productID = productID; this.description = description; this.maker = maker; this.price = price; } public int getProductID() { return productID; } public String getDescription() { return description; } public String getMaker() { return maker; } public int getPrice() { return price; } public void showInfo() { System.out.println("상품 ID >> " + (this.getProductID()+1)); System.out.println("상품설명 >> " + (this.getDescription())); System.out.println("생산자 >> " + (this.getMaker())); System.out.println("가격 >> " + (this.getPrice())); } }
public class Book extends Product { private int ISBN; private String title; private String author; public Book(int productID, String description, String maker, int price, int ISBN, String title, String author) { super(productID, description, maker, price); this.ISBN = ISBN; this.title = title; this.author = author; } public int getISBN() { return ISBN; } public String getTitle() { return title; } public String getAuthor() { return author; } @Override public void showInfo() { super.showInfo(); System.out.println("국제표준도서번호 >> " + this.ISBN); System.out.println("제목 >> " + this.getTitle()); System.out.println("저자 >> " + this.getAuthor()); } }
public class CompactDisc extends Product { private String albumTitle; private String artist; public CompactDisc(int productID, String description, String maker, int price, String albumTitle, String artist) { super(productID, description, maker, price); this.albumTitle = albumTitle; this.artist = artist; } public String getAlbumTitle() { return albumTitle; } public String getArtist() { return artist; } @Override public void showInfo() { super.showInfo(); System.out.println("앨범 제목 >> " + this.getAlbumTitle()); System.out.println("가수 >> " + this.getArtist()); } }
public class ConversationBook extends Book { private String language; public ConversationBook(int productID, String description, String maker, int price, int ISBN, String title, String author, String language) { super(productID, description, maker, price, ISBN, title, author); this.language = language; } public String getLanguage() { return language; } @Override public void showInfo() { super.showInfo(); System.out.println("언어 >> " + this.getLanguage()); } }
import java.util.Scanner; public class ProductTest { // 클래스 영역에 올라감(공유) static int productID = 0; static int numberOfProduct = 0; static Product[] product = new Product[10]; static Scanner scan = new Scanner(System.in); public static void main(String[] args) { int choice = 0; while(choice != 3) { int type = 0; System.out.println("----------상품 조회, 추가 프로그램----------"); System.out.print("상품 추가(1), 상품 조회(2), 종료(3) >> "); choice = scan.nextInt(); if(choice < 1 || choice > 3) { System.out.print("잘못 입력함 다시 압력 : "); choice = scan.nextInt(); } switch(choice) { case 1: if(numberOfProduct >= product.length) { System.out.println("더이상 상품 추가 불가"); break; } System.out.print("책(1), 음악CD(2), 회화책(3) >> "); type = scan.nextInt(); if(type < 1 || type > 3) { System.out.println("잘못 입력함"); break; } // 물품추가 기능 addProduct(type); break; case 2: for(int i=0; i<numberOfProduct; i++) { product[i].showInfo(); } break; case 3: System.out.println("프로그램 종료"); break; } } } private static void addProduct(int type) { scan.nextLine(); // 버퍼비우기 (엔터키) System.out.print("상품설명 >> "); String des = scan.nextLine(); System.out.print("생산자 >> "); String maker = scan.nextLine(); System.out.print("가격 >> "); int price = scan.nextInt(); scan.nextLine(); // 버퍼비우기 switch(type) { case 1: System.out.print("-일반책 제목 >> "); String title = scan.nextLine(); System.out.print("-저자 >> "); String author = scan.nextLine(); System.out.print("-국제표준도서번호(ex.0001) >> "); int ISBN = scan.nextInt(); // 필드의 다형성 (조상타입의 배열에 자손의 인스턴스를 담고 있음) product[numberOfProduct] = new Book(productID++, des, maker, price, ISBN, title, author); break; case 2: System.out.print("-앨범 제목 >> "); String albumTitle = scan.nextLine(); System.out.print("-가수 >> "); String artist = scan.nextLine(); // 필드의 다형성 (조상타입의 배열에 자손의 인스턴스를 담고 있음) product[numberOfProduct] = new CompactDisc(productID++, des, maker, price, albumTitle, artist); break; case 3: System.out.print("-회화책 제목 >> "); String title2 = scan.nextLine(); System.out.print("-저자 >> "); String author2 = scan.nextLine(); System.out.println("-국제표준도서번호(ex.0001) >> "); int ISBN2 = scan.nextInt(); System.out.print("-언어 >> "); String language = scan.nextLine(); // 필드의 다형성 (조상타입의 배열에 자손의 인스턴스를 담고 있음) product[numberOfProduct] = new ConversationBook(productID++, des, maker, price, ISBN2, title2, author2, language); break; } numberOfProduct++; } }
import java.util.ArrayList; class Animal { public void move() { System.out.println("동물이 움직입니다."); } public void eating() { } } class Dog extends Animal { @Override public void move() { System.out.println("개가 네 발로 달립니다."); } public void herding() { System.out.println("개가 양몰이를 합니다."); } } class Tiger extends Animal { @Override public void move() { System.out.println("호랑이가 네 발로 뜁니다."); } public void hunting() { System.out.println("호랑이가 사냥을 합니다."); } } class Eagle extends Animal { @Override public void move() { System.out.println("독수리가 하늘을 날아갑니다."); } public void fly() { System.out.println("독수리가 날개를 펴고 멀리 날아갑니다."); } } public class AnimalTest { public static void main(String[] args) { Animal dAnimal = new Dog(); Animal tAnimal = new Tiger(); Animal eAnimal = new Eagle(); AnimalTest aTest = new AnimalTest(); aTest.moveAnimal(dAnimal); aTest.moveAnimal(tAnimal); aTest.moveAnimal(eAnimal); System.out.println(); ArrayList<Animal> animalList = new ArrayList<>(); animalList.add(dAnimal); animalList.add(tAnimal); animalList.add(eAnimal); for(Animal animal : animalList) { animal.move(); } } public void moveAnimal (Animal animal) { animal.move(); } }
'개발자 수업 > Java' 카테고리의 다른 글
과제2 - CarTest (0) 2021.10.13 15. 추상 클래스와 인터페이스 (0) 2021.10.13 13. Review (0) 2021.10.11 12. 상속과 오버라이딩 (0) 2021.10.08 과제1 - TwoDArrayTest03 (0) 2021.10.08