Java | 다형성(Polymorphism)

바다·2023년 5월 18일
0

Java

목록 보기
5/18
post-thumbnail

다형성 Polymorphism

다형성이란?

하나의 인스턴스가 여러 가지 타입을 가질 수 있는 것을 의미한다. 그렇기 때문에 하나의 타입으로 여러 타입의 인스턴스를 처리할 수 있기도 하고, 하나의 메소드 호출로 개체별로 각기 다른 방법으로 동작하게 할 수도 있다.
다형성은 객체지향 프로그램의 4대 특징 (추상화, 상속, 다형성, 캡슐화) 중 하나이며, 객체지향 프로그래밍의 꽃이라고 불리울 정도로 활용성이 높고 장점이 많다.

  • 하나의 코드가 여러 자료형으로 구현되어 실행되는 것
  • 같은 코드에서 여러 다른 실행 결과가 나옴
  • 다형성을 잘 활용하면 유연하고 확장성 있고, 유지보수가 편리한 프로그램을 만들 수 있음

다형성의 장점

  1. 여러 타입의 객체를 하나의 타입으로 관리할 수 있기 때문에 유지보수성과 생산성이 증가된다.
Animal[] arr = new Animal[5];
arr[0] = new Dog();
arr[1] = new Cat();
arr[2] = new Rabbit();
arr[3] = new Pig();
arr[4] = new Mouse();

for(Animal animal : arr) {
	animal.cry();
}
  1. 상속을 기반으로 한 기술이기 때문에 상속관계에 있는 모든 객체는 동일한 메세지를 수신할 수 있다. 이런 동일한 메세지를 수신받아 처리하는 내용을 객체별로 다르게 할 수 있다는 장점을 가지고 있다. (다양한 기능을 사용하는데 있어서 관리해야 하는 메세지 종류가 줄어들게 된다.)
arr[0].runDog();
arr[1].runCat();
arr[2].runRabbit();
arr[3].runPig();
arr[4].runMouse();
// 모든 메세지를 다 기억하고 사용해야 한다.

for(Animal animal : arr) {
	animal.run();
}
// 관리해야 하는 메세지 수가 줄어든다.
  1. 확장성이 좋은 코드를 작성할 수 있다.
run(new Dog());
run(new Cat());
// 새로운 동물 추가 시 run 메소드를 더 만들지 않아도 된다.

public void run(Animal animal) {
	animal.run();
}
  1. 결합도를 낮춰서 유지보수성을 증가시킬 수 있다.
// 한식을 먹을 경우
public void eat(한식) {
	한식.먹어라();
}

// 음식이 양식으로 바뀌는 경우
public void eat(양식) {
	양식.먹어라();
}

// 한식, 양식 둘 다 가능하도록, 어느 한 쪽을 의지하지 않게 만듦
public void eat(음식) {
	음식.먹어라();
}

동적 바인딩

  • 컴파일 당시에는 해당 타입의 메소드와 연결되어 있다가 런타임 시 실제 해당 인스턴스가 메소드(오버라이딩한 메소드)로 바인딩이 바뀌어 동작하는 것을 의미한다.
  • 조건 : 상속 관계를 가지는 부모 자식 클래스에 오버라이딩 된 메소드를 호출해야 한다.
Animal animal = new Tiger();
animal.cry();

//실제로 동작하는 것은 호랑이 인스턴스이다.

업캐스팅과 다운캐스팅

  • 상속관계에 있지만 오버라이딩 한 것이 아닌 후손 객체가 고유하게 가지는 확장된 기능을 사용하기 위해서는 실제인스턴스의 타입으로 다운캐스팅(클래스 형변환)을 해주어야 한다.
  • 클래스 형변환은 상위 타입 형변환(up-casting)과 하위 타입 형변환(down-casting)이 있다. 상위 타입 형변환의 경우 묵시적으로 일어나며, 하위타입 형변환은 명시적으로 작성해야 한다.
// 업캐스팅(up-casting)
// 명시적
Animal animal = (animal) new Tiger();

//묵시적
Animal animal = new Tiger();

// 다운캐스팅(down-casting) : 묵시적 불가, 명시적으로만 가능
// 컴파일 시 animal의 type은 animal이기 때문에 Tiger 클래스의 멤버에 접근이 불가능하다.
// 멤버가 존재하는 타입으로 다운캐스팅 해 주어야 한다.

((Tiger) aniaml).bite();

Instanceof

  • 원래 인스턴스의 형이 맞는지 여부를 체크하는 키워드

  • 맞으면 true 아니면 false를 반환함

  • 클래스 형변환의 경우 런타임 시 존재하는 타입과 형변환하려는 타입이 일치하지 않는 경우 ClassCastException이 발생한다. 그렇기에 조금 더 런타임 시 안전한 형변환을 하기 위해 instanceof 연산자를 이용할 수 있다.

  • instanceof 연산자는 레퍼런스 변수가 실제로 클래스 타입의 인스턴스인지 확인하여 true or false를 반환한다.

if ( animal instanceof Human) {
		Human human = (Human)animal;
		human.readBooks();
	} else if( animal instanceof Tiger) {
		Tiger tiger = (Tiger)animal;
    	tiger.hunting();
	} else if( animal instanceof Eagle) {
		Eagle eagle = (Eagle)animal;
    	eagle.flying();
    } else {
    	System.out.println("error");
    }
profile
ᴘʜɪʟɪᴘᴘɪᴀɴs 3:14

0개의 댓글