10. 다형성


1. 다형성

a. 다형성이란

  • 부모 클래스 타입의 참조변수로 자식클래스의 인스턴스를 참조

    Parent p = new Child();

    • 부모의 참조변수로는 부모의 멤버들만 사용
    • 오버라이딩 메서드의 경우 자식 메서드 호출
    • 반대의 경우는 불가
  • 한 타입의 참조변수로 여러 타입의 객체를 참조
    • 부모 타입이 파생된 모든 자식타입을 가리킬 수 있다.
  • 여러 개의 개별 클래스를 하나의 부모클래스로 통합관리
    • 부모 타입의 변수로 자식 타입을 일관되게 관리할 수 있다.

b. 다형성 이용

  • ex1 ```java class Parent{ public void parentFunc() { System.out.println(“부모메서드”); } public void showInfo() { System.out.println(“parent-showinfo”); } }

class Child extends Parent{ public void showInfo() { System.out.println(“child-showinfo-오버라이딩”); } public void childFunc() { System.out.println(“자식만의 메서드”); } }

public class PolymoTest {

public static void main(String[] args) {
	Child ch = new Child();
	ch.showInfo();
	ch.parentFunc();
	ch.childFunc();
	
	//다형성
	Parent p = new Child(); // 부모의 참조변수로 자식의 인스턴스 참조
	p.showInfo(); // 자식의 오버라이딩 메서드 호출
	p.parentFunc(); // 부모의 메서드 호출
	//p.childFunc(); // error 자식만의 메서드는 호출 불가
} } ``` - ex2 ```java import java.util.Scanner;

class Shape{ public void draw() { System.out.println(“도형 메서드”); } public void delete() { System.out.println(“도형 삭제 메서드”); } public void display() { System.out.println(“부모 메서드”); } } class Circle extends Shape{ public void draw() { System.out.println(“원 메서드”); } public void delete() { System.out.println(“원 삭제 메서드”); } public void display() { System.out.println(“원 자식 메서드”); }

} class Triangle extends Shape{ public void draw() { System.out.println(“삼각형 메서드”); } public void delete() { System.out.println(“삼각형 삭제 메서드”); } public void display() { System.out.println(“삼각형 자식 메서드”); }

}

public class PolymoTest2 {

public static void main(String[] args) {
	//기본 사용법
	Circle c = new Circle();
	c.draw();
	c.delete();
	
	//다형성 이용
	Shape sh = new Circle();
	sh.draw();
	sh.delete();
	sh.display();
	
	sh = new Triangle();
	sh.draw();
	sh.delete();
	
	//사용자로부터 입력
	Scanner sc = new Scanner(System.in);
	System.out.println("도형 선택 1 원 2 삼각형");
	int type = sc.nextInt();
	
	if(type==1) {
		Circle c2 = new Circle();
		c2.draw();
		c2.delete();
	}else if(type==2) {
		Triangle tr = new Triangle();
		tr.draw();
		tr.delete();
	}else {
		System.out.println("잘못선택");
	}

	// 다형성 이용
	Shape sh2= null;
	if(type==1) {
		sh2=new Circle();
	}else if(type==2) {
		sh2=new Triangle();
	}else {
		System.out.println("잘못입력");
	}
	sh2.draw();
	sh2.delete();
}

}

- ex3 모듈화
```java
import java.util.Scanner;

public class ClassArgsTest {

	// 1. 매개변수가 클래스인 경우
	public static void func1(Circle c) {
		// 참조변수가 보이면 참조변수.메서드
		c.draw();
		c.delete();
		c.sayCircle();
	}
	// 2. 매개변수 다형성
	public static void func2(Shape sh) {
		sh.draw();
		sh.delete();
	}
	
	// 3. 반환타입이 클래스인 경우
	public static Circle func3() {
		Circle c = new Circle();
		return c; // Circle 객체 리턴
	}
	
	//반환타입에 다형성 이용
	public static Shape createShape(int type) {
		Shape sh2= null;
		if(type==1) {
			sh2=new Circle();
		}else if(type==2) {
			sh2=new Triangle();
		}
		return sh2;
	}// 반환타입이 부모클래스면, 자식객체 리턴
	
	public static void main(String[] args) {
		// 1. 매개변수 클래스인 경우 호출
		func1(new Circle());

		Circle c = new Circle();
		func1(c);

		// 2. 매개변수 다형성
		func2(new Circle());
		
		Shape sh = new Circle();
		func2(sh);
		
		// 3. 반환타입이 클래스인 경우
		func1(func3());
		
		Circle c2 = func3();
		func1(c2);
		
		// 4. 반환타입 다형성
		Scanner sc = new Scanner(System.in);
		int type = sc.nextInt();
		Shape sh2 = createShape(type);
		func2(sh2);
	}
}

c. 배열 이용

public class PolymoTest33 {

	public static void main(String[] args) {
		Shape[] arr = new Shape[3];
		arr[0] = new Circle() ;
		arr[1] = new Triangle();
		arr[2] = new Circle();
		
		for(int i = 0; i<arr.length;i++) {
			arr[i].draw();
			arr[i].delete();
		}
		for(Shape i : arr) {
			i.draw();
			i.delete();
		}
	}
}


2. 참조변수의 형변환

a. 기본

  • 참조형 변수도 형변환 가능
    • 상속관계에 있는 클래스 사이에서만 가능
    • 다형성 또한 자동 형변환

      부모<-자식 (Up-casting) : 자동형변환
      자식<-부모 (down-casting) : 명시적 형변환
      Parent p = (Parent)new Child(); // 생략가능, 자동형변환
      Child c = (Child)p; //생략불가
      Child c = (Child)new Parent(); //runtime 에러 (컴파일은 됨)

class Car{
	protected String color;
	protected int door;
	
	public void drive() {
		System.out.println("drive");
	}
	public void stop() {
		System.out.println("stop");
	}
}

class FireEngine extends Car{
	public void water() {
		System.out.println("water");
	}
	public void drive() {
		System.out.println("fire engine drive");
	}
}

class Ambulance extends Car{
	public void siren() {
		System.out.println("siren");
	}
	public void drive() {
		System.out.println("Ambulance drive");
	}
}

public class DownCasting {

	public static void main(String[] args) {
		Car c = new FireEngine(); // 업캐스팅, 다형성, 자동형변환
		c.drive();
		//c.water; //error 자식만의 메서드 호출 불가
		
		FireEngine f = (FireEngine)c; // 다운캐스팅, 명시적 형변환
		f.water(); //자식메서드 호출 가능해짐
		
		//FireEngine fe = (FireEngine)new Car(); //컴파일은 되지만 실행에러
		
		//Ambulance a = (Ambulance)c; //불가, 현재 c에 fireengine이 들어있기 때문

	}

}

b. instance of

  • 참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위한 연산자

    참조변수 instanceof 타입(클래스명)

  • 다운캐스팅 전, 가능한지 확인
  • 주로 조건문에 사용
  • 결과로 boolean값 반환
class Car{
	protected String color;
	protected int door;
	
	public void drive() {
		System.out.println("drive");
	}
	public void stop() {
		System.out.println("stop");
	}
}

class FireEngine extends Car{
	public void water() {
		System.out.println("water");
	}
	public void drive() {
		System.out.println("fire engine drive");
	}
}

class Ambulance extends Car{
	public void siren() {
		System.out.println("siren");
	}
	public void drive() {
		System.out.println("Ambulance drive");
	}
}

public class DownCasting {

	public static void main(String[] args) {
		Car c = new FireEngine(); // 업캐스팅, 다형성, 자동형변환
		c.drive();
		//c.water; //error 자식만의 메서드 호출 불가
		
		FireEngine f = (FireEngine)c; // 다운캐스팅, 명시적 형변환
		f.water(); //자식메서드 호출 가능해짐
		
		//FireEngine fe = (FireEngine)new Car(); //컴파일은 되지만 실행에러
		
		c = new Ambulance();
		Ambulance am = (Ambulance)c;
		am.siren();
		
		if(c instanceof FireEngine) {
			FireEngine f2 = (FireEngine)c;
			f2.water();
		}else if(c instanceof Ambulance) {
			Ambulance am2 = (Ambulance)c;
			am2.siren();
		}else System.out.println("형변환 불가");
	}
}
  • 자식 instanceof 부모 : true
    • 자식은 부모의 인스턴스를 모두 갖고있다
    • fireengine instanceof car : true
    • car instanceof fireengine : false

3. 매개변수의 다형성

class test{
	
	public static void action(Robot a) { // 매개변수로 부모클래스를 넣어 다형성 이용
		if (a instanceof DanceRobot) {
			DanceRobot dr = (DanceRobot)a;
			dr.dance();
		}else if (a instanceof SingRobot) {
			SingRobot sr = (SingRobot)a;
			sr.sing();
		}else if (a instanceof DrawRobot) {
			DrawRobot drr = (DrawRobot)a;
			drr.draw();
		}
	}
	
	public static void main(String[] args) {
		Robot[] arr = { new DanceRobot(), new SingRobot(), new DrawRobot()};
		for(int i=0; i< arr.length;i++) {
			action(arr[i]);
		}
		
		for(Robot i : arr) action(i);
	} // main
}
class Robot {}
class DanceRobot extends Robot {
	void dance() {
	System.out.println("춤을 춥니다.");
	}
}
class SingRobot extends Robot {
	void sing() {
	System.out.println("노래를 합니다.");
	}
}
class DrawRobot extends Robot {
	void draw() {
	System.out.println("그림을 그립니다.");
	}
}