< 다형성(Polymorphism) >
❏ 다형성이 무엇인가?
polymorphism은 poly(여러개) 와 morphism(형태)의 합성어이다.
말그대로 여러개의 형태를 의미한다.
객체지향에서 하위 클래스는 상위클래스로 형변환(업캐스팅)이 가능하다.
예를 들어서 동물이라는 클래스를 개, 고양이, 도마뱀이라는 클래스가 상속하고 있다.
class Animal {
void info(){
System.out.println("나는 동물 입니다.");
}
}
class Dog extends Animal{
@Override
void info() {
System.out.println("나는 개입니다.🐕");
}
void woof() {
System.out.println("멍멍멍멍");
}
}
class Cat extends Animal {
@Override
void info() {
System.out.println("나는 고양이입니다.🐱");
}
void meow() {
System.out.println("야옹~야옹~");
}
}
class Lizard extends Animal {
String sexuality;
@Override
void info() {
System.out.println("나는 도마뱀입니다.🦎");
}
}
Animal의 info클래스를 각각의 하위 클래스에서 이름에 맞게 재정의를 해줬다.
public class AnimalTest {
public static void main(String args[]) {
// 다형성을 이용하여 같은 참조변수로 선언하기
Animal dog = new Dog();
Animal cat = new Cat();
Animal lizard = new Lizard();
// 재정의한 메소드 실행
dog.info();
cat.info();
lizard.info();
}
}
<출력결과>
나는 개입니다.🐕
나는 고양이입니다.🐱
나는 도마뱀입니다.🦎
상위 클래스인 Animal로 타입을 지정하고 new로 만든 인스턴스는 각각 하위 클래스로 지정해줄 수 있다.
이렇게 하위 클래스로 만들고 상위 클래스로 타입을 바꾸는 것을 '업캐스팅'이라고 한다.
상속 계층도에서 위로 올라가서 업캐스팅이라고 생각하자. (반대는 아래로 가니까 다운캐스팅)
자바에서는 업캐스팅은 별다른 키워드 없이 암묵적으로 가능하다.
이것을 '묵시적 형변환' 이라고도 한다.
하지만 반대로 암묵적으로 다운캐스팅(상위클래스 ➡️ 하위클래스)은 불가하다!!
상위 클래스로 인스턴스를 만든 후에 하위 클래스로 다운 캐스팅하게 되면 사진처럼 빨간 줄이 그어지고 오류가 난다.
❏ 왜 업캐스팅은 묵시적으로 되지만 다운캐스팅은 안될까?
하위 클래스들은 상위 클래스보다 구체적이고 메소드나 멤버변수가 같거나 많다.
하지만 상위 클래스는 더 일반적으로 만들어서 메소드나 멤버변수가 같거나 적다.
그래서 상위 클래스로 만든 인스턴스를 하위 클래스 타입의 메모리 공간에 집어넣으면
일부 메소드와 멤버변수를 사용할 수 없는 일이 발생한다.
실제로 클래스 내에 정의된 멤버변수와 메소드를 쓸 수 없어서 에러가 발생한다.
반대로 하위 클래스로 만든 인스턴스를 상위 클래스 타입의 메모리에 넣는건
인스턴스 만들 떄 있던 일부 기능이나 속성을 사용하지는 못하더라도 상위 클래스에 정의된 모든 메소드나 멤버변수는 사용할 수 있다.
내용물은 하위 클래스더라도 참조 타입은 상위 클래스이기 때문에 문제될 것은 없는 것이다.
참고) 상위 클래스 위의 상위 클래스들도 묵시적으로 형변환이 가능할까?
상속 계층이 여러 층일 때 여러 층 위의 상위 클래스로의 형변환도 묵시적으로 이루어진다.
❏ instanceof 를 통한 다운 캐스팅
상위 클래스로 형변환 했던 하위 클래스를 다시 원래 자료형으로 돌려놓을 수는 없을까?
하위 클래스로 직접적으로 형변환 할 수는 없지만 instanceof라는 키워드를 사용하면 원래 형태가 하위 클래스인지 확인할 수는 있다.
instanceof 예약어는 왼쪽에 있는 변수의 원래 인스턴스 형이 오른쪽 클래스 자료형인지 확인해준다.
➡️ 원래 자료형이 맞으면 true / 틀리면 false 를 반환한다.
주로 if 문과 함께 사용한다.
하위 클래스를 업 캐스팅하면 상위 클래스에 없는 해당 클래스의 고유한 메소드나 필드는 사용할 수 없게 된다.
위에 작성한 예시 코드에서 Dog와 Cat 클래스에는 상위 클래스에서 재정의한 메소드가 아닌 woof()와 meow()메소드가 있다.
그리고 Lizard에는 스트링 타입의 성별 멤버 변수가 선언되있다.
상위 클래스에서 정의 하지 않은 woof()와 meow(), sexuality를 업캐스팅한 변수에서 접근해보았다.
public static void main(String args[]) {
// 다형성을 이용하여 같은 참조변수로 선언하기
Animal dog = new Dog();
Animal cat = new Cat();
Animal lizard = new Lizard();
Lizard example = new Animal();
// 하위클래스에만 있는 메소드 실행
dog.woof(); // cannot find symbol 오류
cat.meow(); // cannot find symbol 오류
// 하위 클래스에만 있는 필드 실행
lizard.sexuality = "female"; // cannot find symbol 오류
}
실행하게 되면 'cannot find symbol' 에러가 뜨게 된다.
상위 클래스로 형변환하면서 하위 클래스에만 있던 메소드와 필드는 메모리 할당이 되지 않아 사용할 수 없게 된 것이다.
이럴 때 instanceof 를 사용해서 원래 자료형을 확인하고 맞으면 원래 인스턴스형강제로 다운캐스팅 해주면 된다.
원래 인스턴스형으로 변환할 때는 괄호안에 원래 자료형을 반드시 명시해야한다.
상위 클래스로 형변환 했던 객체를 다시 원래 자료형으로 형변환하는 것을 '다운캐스팅'이라고 부르기도 한다.
public static void main(String[] args) {
// 상위 클래스로 형변환
Animal dog = new Dog();
Animal cat = new Cat();
Animal lizard = new Lizard();
// instanceof를 이용한 다운캐스팅
if (dog instanceof Dog) {
Dog dog1 = (Dog)dog;
dog1.woof();
}
if (cat instanceof Cat) {
Cat cat1 = (Cat)cat;
cat1.meow();;
}
if (lizard instanceof Lizard) {
Lizard lizard1 = (Lizard)lizard;
lizard1.sexuality = "female";
System.out.println(lizard1.sexuality);
}
}
<출력결과>
멍멍멍멍
야옹~야옹~
female
업캐스팅과 다운캐스팅에 대한 레퍼런스
https://www.geeksforgeeks.org/upcasting-vs-downcasting-in-java/
읽어주셔서 감사합니다. 도움이 되셨길 바랍니다. 🫶
오개념에 대한 지적은 언제나 환영입니다.
'TIL(Today I Learned)' 카테고리의 다른 글
5/17 (화) 컬렉션 프레임워크-1️⃣ 제네릭(Generic) (0) | 2022.05.17 |
---|---|
5/16 (월) 자바 코딩과 여러가지 오류,, (0) | 2022.05.16 |
5/12 (목) 자바 상속(Inheritance) (0) | 2022.05.12 |
5/11 (수) 객체지향 프로그래밍 기초2 (생성자) (0) | 2022.05.11 |
5/10 (화) 객체지향 프로그래밍 기초 (0) | 2022.05.11 |