객체지향_다형성

소정·2023년 1월 30일
0

Java

목록 보기
14/23
post-thumbnail

다형성(Ploymorphism)이란?

참조변수 하나로 여러개의 객체를 제어하는 것
-> 상속 관계에 있을 때 부모 참조변수로 자식 객체들을 생성하고 제어함 but 버라이드 된 메소드만 가능
참조변수.메소드() 글씨는 같은데 결과가 다르게 나온다 하여 다형성 이라고 부름


public class First {
	int a;
	
	void showFirst() {
		System.out.println("showFirst 입니다");
	}
	
	void show() {
		System.out.println("First 클래스의 show method");
	}
}


public class Second extends First{
	int b;
	
	void showSecond(){
		System.out.println("show Second");
	}
	
	
	@Override
	void show() {
		System.out.println("Second 클래스의 show method");
	}
}


public class Test extends First {


	@Override
	void show() {
		System.out.println("Test의 show");
		System.out.println();
	}
	
}


public class Main {

	public static void main(String[] args) {
		//업캐스팅이 되어도 자식객체의 기능메소드를 사용할 수 있는 경우가 있음 -> 오버라이드 된 메소드 
		//부모 참조변수 1개로 자식객체 모두를 제어할 수 있음 => 다형성
		//같은 참조변수 하나로 부모것도 자식곳도 참조하는 것
		First obj = new First();
		obj.show();
		
		obj = new Second();
		obj.show();
		
		obj = new Test();
		obj.show();
		
	}

}

1) UP casting(=참조)

상속의 관계에 있을 때 부모객체에서 자식객체를 참조할 수 있는 것, 자식 객체를 제어할 수는 있지만 자식객체의 고유의 것은 쓸 수 없다

public class Main {

	public static void main(String[] args) {

		//제대로 된 캐스팅
		First f = new First();
		Second s = new Second();
		
		//다른 class의 객체를 참조하면 에러
		//f= new Second(); // 에러 : Type mismatch: cannot convert from Second to First
		
		//단, 상속 관계의 클래스 라면 가능해짐
		f= new Second(); //부모참조변수로 자식객체를 참조할 수 있음 [UP casting]
		//상속후엔 Second 객체에 first 객체를 가지고 있기 때문에
		//부모 참조변수로 자식객체를 참조하여 제어가능
		f.a = 10;
		f.showFirst();
		//참조는 할 수 있지만 자식객체의 고유기능은 쓸수 없음
		//f.shoSecond();  //에러 : The method shoSecond() is undefined for the type First	
		
	}

}

2) DOWN casting

자식 객체에서 부모객체 제어하려는 것 -> 불가
하지만 상속 관계에서 한번이라도 UP casting이 된 상태에선 다운캐스팅 가능
즉, 자식객체를 참조하는 부모의 참조변수를 참조하여 객체를 공유함

사용법 : (데이터 타입)참조변수
-> ((데이터 타입)참조변수).변수
-> ((데이터 타입)참조변수).메서드()


public class Main {

	
public class Main {

	public static void main(String[] args) {
    	//자식객체의 고유기능을 사용하고싶다면 자식객체를 참조하는 참조변수가 필요 
		//새로운 자식참조변수를 만들고 Second객체를 참조하면 First 참조변수 f의
		//참조값(주소)를 대입해주기 -> 객체 공유
		//Second s2 = f; //error : Type mismatch: cannot convert from First to Second
		//자식(Second)가 부모(First)를 참조한다고 오해함 
		//f가 참조하는것이 Second 객체라고 알려주면 대입 가능(형변환)
		Second s3 = (Second) f; //다운캐스팅
		s3.b = 50;
		s3.showSecond();	
    
		//업캐스팅 되어 있지 않은 경우 다운캐스팅 시도하면 에러
		First f2 = new First();
		//Second s4 = (Second)f2; //다운캐스팅 시도 - 형변환은 객체를 바꾸는 것이 아니고 주소값을 바꾸는것
		//s4.showFirst(); //이클립스에서 오류표시 안남 but 실행하면 오류 -> class First cannot be cast to class Second

		//이런 up, down 캐스팅을 하는 이유
		//이걸 하려면 오버라이드 된 메소드일때 살펴봐야함
		First ff= new Second(); //업캐스팅
		ff.show(); //실제 참조하고 있는 객체의 오버라이드 된 show가 발동됨
		System.out.println();
		
		//업캐스팅이 되어도 자식객체의 기능메소드를 사용할 수 있는 경우가 있음 -> 오버라이드 된 메소드 
		//이 기술을 이용하여 다양하게 활용할 수 있음
		
		//실제 활용현태 실습
		//부모 참조변수 1개로 자식객체 모두를 제어할 수 있음 => 다형성
		//같은 참조변수 하나로 부모것도 자식곳도 참조하는 것
		First obj = new First();
		obj.show();
		
		obj = new Second();
		obj.show();
		
		obj = new Test();
		obj.show();
		
		
		
		//조부모 참조변수로 손주객체 참조가능
		//First - Second - Third
		obj = new Third();
		obj.show();
		
		//이렇게 obj.show(); 라는 글씨는 같은데
		//결과가 다르게 나온다 하여 다형성 이라고 부름

	}

}


다형성 사용이유
보모의 참조변수를 통해 자식객체들을 생성하고 제어할 수 있다


다형성 사용 예시

//Dog, Cat, Pig의 부모클래스
public class Animal {
	//오버라이드용 메소드
	void say() {
	}
	
}


public class Dog extends Animal {

	void say() {
		System.out.println("멍멍");
	}
	
	void gardHouse() {
		System.out.println("집지키기");
	}
	
}


public class Cat extends Animal {

	void say() {
		System.out.println("야옹");
	}
	
	void handling() {
		System.out.println("왔니");
	}
	
}


public class Pig extends Animal {

	void say(){
		System.out.println("꿀꿀");
	}
	
	void eatAndEat() {
		System.out.println("냠냠");
	}
	
}

1)다른 타입의 객체를 하나의 배열로 묶을 수 있다

-> 배열은 같은 타입의 변수들을 묶는 것 인데 다형성을 사용하면 서로 다른 객체를 부모클래스의 참조변수로 하나의 배열로 묶어 관리 할 수 있다

Animal ani = new Dog(); //업캐스팅
	ani.say();
	System.out.println();
		
	//배열로 자식객체들 묶기
	Animal anis[] = new Animal[3];
		
	anis[0] = new Dog(); //UP casting
	anis[1] = new Cat();
	anis[2] = new Pig();
		
	anis[0].say();
	anis[1].say();
	anis[2].say();
		
	System.out.println();
	//반목문
	for (int i = 0; i < anis.length; i++) {
		anis[i].say();
	}
		
	System.out.println();
	//확장
	for(Animal t : anis) {
		t.say();
	}

2)메소드의 파라미터나 리턴타입을 묶을 수 있다


public class AnimalFctory extends Animal{
	
	//애니멀 객체를 생성하여 리턴해주는 기능메소드
	
	/*
	 * Animal makeAnimal(int num) {
	 * 
	 * switch (num) { case 1: Animal d = new Dog(); return d; case 2: Animal c = new
	 * Cat(); return c; case 3: Animal p = new Pig(); return p; default:
	 * System.out.println("잘못선택"); return null; } }
	 */
	
	Animal makeAnimal(int num) {
		
		Animal ani = null;
		
		switch (num) {
		case 1:
			ani = new Dog(); //리턴 타입을 공통인 Animal로 묶어 관리
			break;
		case 2:
			ani = new Cat();
			break;
		case 3:
			ani = new Pig();
			break;
		}
		
		return ani;
	}
	
}


AnimalFctory af = new AnimalFctory();
		
	//makeAnimal은 Animal을 리턴하는데 
	//다운캐스팅으로 타입을 맞춰줌
	Dog d = (Dog)af.makeAnimal(1); 
	d.say(); //오버라이드 된 기능
	d.gardHouse(); //고유기능
	System.out.println();

 	Cat c = (Cat)af.makeAnimal(2); 
	c.say();
	c.handling();
	System.out.println();
		
	Pig p = (Pig)af.makeAnimal(3); 
	p.say();
	p.eatAndEat();
	System.out.println();
		
	//Animal 참조변수 1개로 여러갟체 제어하기 -> 배열
	//편하지만 자식객체만의 고유기능은 사용불가
	Animal ani = null;
		
	ani = af.makeAnimal(1);
	ani.say();
	//자식객체의 고유기능을 사용하려면 다운캐스팅 해야함
	Dog dog = (Dog)ani;
	dog.gardHouse();

	ani = af.makeAnimal(2);
	ani.say();
	((Cat)ani).handling(); // . 이 연산자 우선순위가 높아서 ()로 묶어준다
		
		
	ani = af.makeAnimal(3);
	ani.say();
	((Pig)ani).eatAndEat();

3)랜덤하게 만들어서 공통기능과 고유기능 시용과 instanceof

//3. 캐릭터 5마리를 랜덤하게 만들어서 공통기능과 고유기능 시용
	//랜덤 값을 만들어 내는 객체생성
	Random rnd = new Random();
	//동물 참조변수 5개를 가진 배열 생성
	Animal[] anis = new Animal[5];
		
	for (int i = 0; i < anis.length; i++) {
		int n = rnd.nextInt(3) + 1; // 1,2,3
		anis[i] = af.makeAnimal(n);
	}
		
	System.out.println();
	
	//각 객체들 기능 호출
	for (int i = 0; i < anis.length; i++) {
		//동물들의 공통기능
		anis[i].say(); // 오버라이드 된 메소드 발동
			
		//고유기능
		// anis[i]번째 참보변수가 어떤 클래스인지 알아야 다운캐스팅하고 
		//고유 기능을 사용할 수 있음
		//탐조변수가 어떤 클래스의 객체를 참조하고 있는지 알려주는 연산자 : instanceof
		if(anis[i] instanceof Dog) {
			Dog ddd = (Dog)anis[i];
			ddd.gardHouse();
		} else if(anis[i] instanceof Cat) {
			((Cat)anis[i]).handling();
		} else if(anis[i] instanceof Pig) {
			((Pig)anis[i]).eatAndEat();
		}
		
	}

instanceof
참조변수가 어떤 클래스의 객체를 참조하고 있는지 알려주는 연산자

-> 사용하는 이유 : 다형성으로 인해 여러 타입이 전달될 수 있으므로 각각의 인스턴스 타입에 따라 서로 다른 작업을 하기 위해

if(참조변수 instanceof 클래스이름) {실행문;}



상속과 다형성의 차이 생각해보기
상속은 자식객체에서 부모의 객체를 참조하는 것이고 다형성은 부모객체의 참조변수 하나로 자식 객체들을 모두 제어할 수 있는 것
하지만 상속에서도 다형성에서도 자식객체의 고유기능은 사용할 수 없는 공통점이 있다
자식 객체의 고유 기능을 사용하고 싶으면 다운캐스팅을 사용해 강제로 명시해주면 접근 가능하다~!

profile
보조기억장치

0개의 댓글