ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • 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

    댓글