╱╱╭╮╱╱╱╱╱╱╭━━━╮╱╱╱╭╮╱╭╮╱╱╱╱╱╱ ╱╱┃┃╱╱╱╱╱╱┃╭━╮┃╱╱╱┃┃╱┃┃╱╱╱╱╱╱ ╱╱┃┣━━┳━━╮┃┃╱┃┣━╮╱┃╰━╯┣━━┳━╮╱ ╭╮┃┃╭╮┃┃━┫┃╰━╯┃╭╮╮┃╭━╮┃╭╮┃╭╮╮ ┃╰╯┃╭╮┃┃━┫┃╭━╮┃┃┃┃┃┃╱┃┃╭╮┃┃┃┃ ╰━━┻╯╰┻━━╯╰╯╱╰┻╯╰╯╰╯╱╰┻╯╰┻╯╰╯

Java/Java 기초

[Java] 객체지향 언어 특징(다향성 Polymorphism)

재안안 2022. 4. 15. 04:21

클래스를 이해하는데 있어서 알아야하는 중요한 개념이 있다.

객체지향 언어의 특징이다.

객체지향 언어의 특징은 아래와 같다.

 

  • 추상화
  • 상속성
  • 다형성
  • 캡슐화

 

이번에 알아볼 다형성은 상속성과 연관이 있다.

 

상속성이 클래스간의 부모자식 관계를 만든다면

다형성은 부모자식 클래스간의 필드와 메소드의 다형성을 뜻한다.

 

  • 다향성(Polymorphism)

 

우선 자바에서 다형성(Polymorphism)이란 하나의 객체가 다양한 형태(타입)를 가질 수 있음을 뜻한다.

 

예를들면 int num=1;
num은 int형이지만 float, char와 같은 여러가지 형태를 가질 수 도 있다. (형변환)

이로인해 클래스의 형변환도 생각할 수 있다.

 

그런데 클래스의 형변환은 제약이 많다.

클래스 형변환은 부모자식 관계의 클래스끼리만 가능하다.

클래서 형변환은 명시적형변환으로 실행된다.

 

클래스 형변환엔 업캐스팅(upcasting)과 다운캐스팅(downcasting)이 있다.

 

우선 업캐스팅이란 자식클래스의 객체가 부모클래스로 형변환 되는 것이고
다운캐스팅이란 업캐스팅 되었던 부모클래스 객체가 자식클래스로 형변환되는 것이다.

 

우선 "업캐스팅"먼저 아래의 클래스들을 통해 알아보겠다.

 

Wolf -> Predator

 

Predator 클래스는 1개의 메소드

Wolf 클래스는 2개의 메소드를 가지고있다.

 

 

아래의 메인 클래스를 통해 업캐스팅의 방식을 설명하겠다.

업캐스팅 예제

업캐스팅은 위와같이 구현한다.

 

참조변수 wolf는 Wolf 클래스를 참조하고있다.

그런데 아래를 보면 참조변수 predator1은 Predator로 upcasting된 wolf를 참조하고있다. (명시적 형변환 사용)

그리고 참조변수 predator2는 Wolf 클래스를 참조하고있다.

 

 

결과적으로 predator1predator2 모두 Wolf 클래스를 참조하여도

predator1과 predator2는 모두 Predator의 인스턴스이다.

 

그럼이제 실행결과를 보겠다.

 

실행 결과

 

분명 predator1predator2Predator의 인스턴스이다.

그런데 왜 Predator 클래스 내에 있는 hunt 메소드가 실행되지 않을 것일까?

 

자바는 모든 메소드가 동적바인딩(Dynamic Binding)의 방식으로 실행되기 때문이다.

동적바인딩에 대한 자세한 설명은 다음에 하겠다.

 

자바의 모든 메소드가 동적바인딩의 방식으로 실행되기 때문에 메소드 오버라이딩이 가능한 것이다.

메소드 앞에 static을 붙여 정적바인딩으로 설정하면 메소드 오버라이딩이 안된다.

 

참조변수 predator1를 통해 왜 "늑대가 사냥을 시작합니다."가 출력되었는지 설명하겠다.

 

Wolf wolf = new Wolf();

 

Wolf 클래스가 생성되었고 Wolf는 Predator클래스를 상속받았다.

이때 Predator.hunt()Wolf.hunt()오버라이딩 되었다.

 

Predator predator1 = (predator)wolf;

 

predator1가 업캐스팅된 wolf를 참조한다.

이때 업캐스팅이 되었다고 해도 이미 오버라이드된 함수는(재정의 된 함수는) 그대로 쓴다는 것이다.

 

Wolf Class에는 2개의 메소드가 있었다.

하나는 hunt()이고 다른건 sleep()이다.

 

그런데 sleep()은 안된다.

 

안된다
정의되지 않았다고 뜬다

 

이는 업캐스팅할 때 Wolf.sleep()은 Predator로 넘어오지 못해서 이다.

메모리차이에 의한 데이터 손실이다.

 

자식클래스에서 부모클래스로 업캐스팅 할 때는

자식클래스의 함수, 이 부모클래스로 넘어가는 것이다.

만약 부모클래스에 값, 함수를 담을 공간이 없다면 값, 함수는 그냥 사라진다.

 

 

이제 "다운캐스팅"을 설명하겠다.

 

다운캐스팅은 극히 제한적인 객체만 가능하다.

 

부모클래스에서 자식클래스로 형변환 하는 것인데

업캐스팅 되었던 부모클래스 인스턴스만 자식클래스로 다운캐스팅이 가능하다.

 

쉽게말하자면 한번 올라갔던 거만 내려올 수 있는 것이다. 그냥 내려가는건 할 수 없다.

 

아래의 예제를 통해 설명하겠다.

 

실행 결과

Wolf wolf2 = (Wolf)predator1

다운 캐스팅은 정상적으로 실행이 되었다.

그리고 결과적으로 wolf2.hunt(), wolf2.sleep() 모두 잘 실행된다.

 

이때 Wolf wolf3 = new Predator();는 불가능하다.

분명 Wolf의 메모리가 Predator의 메모리 보다는 커서 이론적으로 들어수 있을거 같지만

자바는 이를 메모리 낭비라고 생각해 허용하지 않는다. 

 

데이터손실은 괜찮지만 메모리 낭비는 안된다고 한다.

 

 

이때 형변환 가능여부를 판별하는 방법이 있다.

 

바로 instanceof를 이용하는 것이다.

 

사용형식은 참조변수 instanceof 클래스이다.

 

instanceof 사용 예제
실행 결과

실행 결과는 "참조변수 -> 클래스"의 출력을 보여준다.

 

instanceof의 결과값이 true면 참조변수의 형변환이 가능한 것이고 

false불가능하다는 것이다.