다형성(poliymorphism)

jungnoeun·2022년 5월 24일
0

java

목록 보기
11/22

🤩다형성

  • 여러가지 형태를 가질 수 있는 능력
  • 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 하는 것
class Tv {
	boolean power;
    int channel;
    
    void power {}
    void channelUp(){}
    void channelDown(){}
}
class CaptionTv extends Tv {
	String text;
    void caption() {}
}

인스턴스의 타입과 참조변수의 타입이 일치하는 것이 보통이지만, Tv와 CaptionTv가 서로 상속관계에 있을경우, 조상클래스 타입의 참조변수로 자손클래스의 인스턴스를 참조할 수 있다.

//일반적인 경우,
Tv t = new Tv();
CaptionTv c = new CaptionTv();

//상속을 통한 다형성
Tv t = new CaptionTv();
CaptionTv c = new CaptionTv();

Tv t = new CaptionTv(); 를 봤을때 참조변수 t가 참조하는 인스턴스가 CaptionTv 타입이어도, 참조변수 t로는 CaptionTv 인스턴스의 모든 멤버를 사용할 수 없다. Tv타입의 참조변수로는 CaptionTv인스턴스 중에서 Tv클래스의 멤버들만 사용할 수 있다.
t와 c는 둘다 같은 타입의 인스턴스지만 참조변수의 타입에 따라 사용할 수 있는 멤버의 개수가 달라진다.



반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은 불가능하다.

CaptionTv c = new Tv(); //에러

그 이유는 실제 인스턴스인 Tv의 멤버 개수보다 참조변수 c가 사용할 수 있는 멤버 개수가 더 많기 때문이다. 그래서 자손타입의 참조변수로 조상타입의 인스턴스를 참조하는 것은 존재하지 않는 멤버를 사용하려할 가능성이 있으므로 허용하지 않는다. 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수보다 같거나 적어야 한다.

  • 조상타입의 참조변수로 자손타입의 인스턴스를 참고할 수 있다.
  • 반대로 자손타입의 참조변수로 조상타입의 인스턴스를 참고할 수는 없다.






🤡참조변수의 형변환

서로 상속관계에 있는 클래스사이에서 참조변수도 형변환이 가능하다.

자손타입 -> 조상타입 (Up-casting) : 형변환 생략가능
자손타입 <- 조상타입 (Down-casting) : 형변환 생략불가

참조변수간 형변환은 캐스트연산자를 사용하며, 괄호()안에 변환하고자 하는 타입의 이름(클래스명)을 적어주면 된다.

형변환 주의점

형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것이 아니기 때문에 참조변수의 형변환은 인스턴스에 아무런 영향을 미치지 않는다. 단지 참조변수의 형변환을 통해서, 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것뿐이다.

참조변수가 가리키는 인스턴스의 자손타입으로 형변환은 허용하지 않는다. 컴파일 시에는 참조변수간의 타입만 체크하기 때문에 실행 시 인스턴스의 타입에 대해서는 알지 못한다. 그래서 컴파일 시에는 문제가 없지만 실행시 에러가 발생한다.





✨instanceof 연산자

참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용한다.
참조변수 instanceof 타입(클래스명)
연산의 결과로 boolean값인 true와 false 중의 하나를 반환하는데, instanceof연산의 결과로 true를 얻었다는 것은 참조변수가 검사한 타입으로 형변환이 가능하다는 의미이다.

class InstanceofTest {
	public static void main(String args[]) {
		FireEngine fe = new FireEngine();

		if(fe instanceof FireEngine) {
			System.out.println("This is a FireEngine instance.");
		}

		if(fe instanceof Car) {
			System.out.println("This is a Car instance.");
		}

		if(fe instanceof Object) {
			System.out.println("This is a Object instance.");
		}
	}
}
실행결과
This is a FireEngine instance.
This is a Car instance.
This is a Object instance.






😊참조변수와 인스턴스의 연결

자손클래스에 조상클래스에 선언된 멤버변수와 같은 이름의 인스턴스변수를 중복으로 정의했을때,
조상타입의 참조변수로 자손 인스턴스를 참조하는 경우와 자손타입의 참조변수로 자손 인스턴스를 참조하는 경우는 서로 다른 경우를 얻는다.

  • 메서드의 경우, 조상클래스의 메서드를 자손 클래스에서 오버라이딩한 경우에도 참조변수의 타입에 관계없이 항상 오버라이딩된 메서드가 호출된다.
  • 멤버변수의 경우, 참조변수의 타입에 따라 달라진다.






🙌매개변수의 다형성

참조변수의 다형적인 특징은 매개변수에도 적용된다.

class Product {
	int price;	// 제품의 가격
	int bonusPoint; // 제품구매 시 제공되는 보너스 점수
}

class Tv extends Product {}
class Computer extends Product {}
class Audio extends Product {}

class Buyer {	// 고객, 물건을 사는 사람
	int money = 1000;
	int bonusPoint = 0;
    
    //매개변수에 다형성 적용
    void buy(Product p) {
    	money = money - p.money;
    	bonusPoint = bonusPoint - p.bonusPoint;
}

매개변수가 Product타입의 참조변수라는 것은, 메서드의 매개변수로 Product클래스의 자손타입의 참조변수면 어느것이나 매개변수로 받아들일 수 있다는 것이다.






😉여러종류의 객체를 배열로 다루기

Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();

//위의 코드를 Product타입의 참조변수 배열로 처리하면 아래와 같다.
Product p[] = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();

이처럼 조상타입의 참조변수 배열을 사용하면, 공통의 조상을 가진 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다.
또는 묶어서 다루고 싶은 객체들의 상속관계를 따져서 가장 가까운 공통조상 클래스 타입의 참조변수 배열을 생성해서 객체들을 저장하면 된다.

profile
개발자

0개의 댓글