[Java]상속의 다형성과 클래스 타입 변환(업캐스팅&다운캐스팅)

Euiyeon Park·2024년 9월 5일
0

Java

목록 보기
11/16
post-thumbnail

해당 포스팅은 한빛 미디어의 혼자 공부하는 자바
유튜브 Yalco님의 강의를 바탕으로 작성했습니다.

🌿 다형성(Polymorphism)

다형성(Polymorphism)이란 하나의 타입에 여러가지 타입의 데이터를 대입하여
다양한 결과를 얻어낼 수 있는 성질을 의미한다.
이를 통해 하나의 객체는 여러가지 형태를 가질 수 있다.

상위 클래스의 참조 변수로 하위 클래스의 참조 변수를 다루거나(Upcasting)
동일한 이름의 메소드를 여러 형태(Override)로 만들 수 있다.

즉, 다형성은 클래스가 상속관계가 있을 때 나타나는 다채로운 성질이다.

🌿 다형성 구현 방법

자바에선 대표적으로 아래의 방법들이 다형성에 속한다.

  • 오버로딩(Overloading)
  • 오버라이딩(Overriding)
  • 업캐스팅(Upcasting)
  • 다운캐스팅(Downcasting)
  • 인터페이스(Interface)
  • 추상메소드(Abstract Method)
  • 추상클래스(Abstract Class)

🌿 클래스 타입 변환

클래스 타입 변환은 상속 관계에 있는 클래스들 사이에서 객체를 다른 타입으로 변환하는 것이다.
자바에서는 주로 업캐스팅(Upcasting)다운캐스팅(Downcasting)을 사용한다.

  • 자식 클래스의 객체는 부모 클래스를 상속하므로 부모의 멤버를 모두 가지고 있다.
  • 반면에 부모 클래스의 객체는 자식 클래스의 멤버를 모두 가지고 있지 않다.

🤍 업캐스팅(Upcasating)

업캐스팅(Upcasting)은 자식 클래스의 객체를 부모 클래스 타입으로 변환하는 것이다.
자바에서 업캐스팅은 자동으로 수행되며, 특별한 연산자나 메서드 호출이 필요하지 않다.
업캐스팅을 통해 부모 클래스 타입의 참조 변수로 자식 클래스의 객체를 다룰 수 있다.

// Animal.java
public class Animal{
	
    public void makeSound(){
    	System.out.println("Animal makes a sound");
    }
}

// Dog.java
public class Dog extends Animal{

	@Override
    public void makeSound(){
    	System.out.println("Bow-Wow");
    }
    
    public void favSnack(){
    	System.out.println("Beef Jerky");
    }
}

// Main.java
public class Main{
    public static void main(String[] args){
    	Dog dog = new Dog();
        Animal animal = dog;	// 업캐스팅
        // 또는 Animal animal = new Dog();
        
        animal.makeSound();		// "Bow-Wow"
        animal.favSnack(); 		// ❌Error
    }
}
  • 자식 클래스 객체 dog 을 부모 클래스 Animal 타입으로 캐스팅(업캐스팅)
  • 부모 클래스로 캐스팅 된다는 것은 멤버의 갯수 감소를 의미한다.
    즉, 자식 클래스에만 있는 속성과 메소드는 실행하지 못한다.
  • 업캐스팅한 뒤에 자식 클래스에서 오버라이딩한 메소드가 있을 경우,
    부모 클래스의 메소드가 아닌 오버라이딩 된 메소드가 실행된다.

🤍 다운캐스팅(Downcasating)

다운캐스팅(Downcasting)은 부모 클래스 타입을 자식 클래스 타입으로 변환하는 것이다.
다운캐스팅은 명시적으로 변환해야 하며, 타입 캐스팅 연산자를 사용한다.

더 명확하게 말하면, 부모 클래스 타입으로 자식 객체를 참조하던 참조변수의 타입을
다시 자식 클래스 타입으로 변환하는 것이다.

다운캐스팅은 단순히 업캐스팅의 반대 개념이 아니다.
다운캐스팅의 진정한 의미는 부모 클래스로 업캐스팅된 자식 클래스를 복구하여
본인의 필드와 기능을 회복하기 위해 있는 것이다.

💡 다운캐스팅을 하기 위한 사전 조건은 업캐스팅이 먼저 이루어진 경우다.

Parnet parent = new Child();	// 업캐스팅
Child child = (Child) parent;	// 다운 캐스팅

// Animal.java
public class Animal{
	
    public void makeSound(){
    	System.out.println("Animal makes a sound");
    }
}

// Dog.java
public class Dog extends Animal{

	@Override
    public void makeSound(){
    	System.out.println("Bow-Wow");
    }
    
    public void favSnack(){
    	System.out.println("Beef Jerky");
    }
}

// Main.java
public class Main{
    public static void main(String[] args){
       Animal animal = new Dog(); 	// 업캐스팅
       
       animal.makeSound();			// "Bow-Wow"
       animal.favSnack(); 			// ❌Error
       
       if(animal instanceof Dog{	// 다운 캐스팅
       		Dog dog = (Dog) animal;
            dog.favSnack();			// ✅Success
    }
}

🪄 instanceof 연산자

다운캐스팅(강제 타입 변환)은 자식 타입이 부모 타입으로 변환되어 있는 상태(업캐스팅)에서만 가능하기에 처음부터 부모타입으로 생성된 객체는 자식 타입으로 변환할 수 없다

Parent parent = new Parent();
Child child = (Child) parent;	// ❌Error

따라서 부모 변수가 참조하는 객체가 부모 객체인지, 자식 객체인지 확인이 먼저 필요하다.

instanceof 연산자는 뒤에 오는 클래스의 자료형에 속하는 인지턴스인지 확인하고
boolean타입(true/false)를 반환한다.

다운캐스팅에서 instanceof를 사용하는 이유는,
해당 객체가 실제로 하위 클래스의 인스턴스인지 확인하기 위해서이다.
이를 통해 ClassCastException같은 런타임 에러를 방지할 수 있다.

// parent가 Child의 인스턴지인지 확인
if(parent instanceof Child){
	Child child = (Child) parent;
}

🌿 클래스 타입 변환 활용

자식 클래스의 인스턴스는 모두 부모 클래스의 자료형에 속하므로
부모 클래스의 범주로 묶어 배열에서 사용 가능하다. - 타입 묶음

class Animal{
}

class Dog extends Animal{
}

class Cat extends Animal{
}

class Hamster extends Animal{
}

Animal[] animals = {
		new Animal(),
        new Dog(),
        new Cat()
};

🌿메모리 상태 확인하기

  • 업캐스팅과 다운캐스팅 과정에서 animaldog은 모두 같은 Dog 객체를 참조한다.

  • Dog 객체를 참조하는 타입의 차이만 있을 뿐, 참조 대상 객체는 동일하다.

    • 업캐스팅에서 animalAnimal타입으로 참조한다.
    • 다운캐스팅에서 dogDog타입으로 참조한다.
  • 객체를 참조하는 타입의 차이로 인해 접근할 수 있는 필드와 메서드가 다를 수 있다.

    • animal을 통해 호출할 수 있는 메소드는 Animal클래스에서 정의된 메서드
    • dog을 통해 호출할 수 있는 메소드는 Dog클래스에서 정의된 메서드

🪄 [참고]모든 클래스들의 최고 조상 Object클래스

Object 클래스는 Java에서 모든 클래스의 최상위 부모 클래스다.
모든 클래스는 암묵적으로 Object 클래스를 상속받는다.

모두의 조상, 모든 자료형을 다룰 수 있다.

  • 모든 클래스는 Object 클래스에서 정의된 메소드를 사용할 수 있다.
    • toString() - 객체를 문자열로 변환
    • equals(Object obj) - 두 객체의 동등성 비교
    • hashCode() - 객체의 해시 코드 반환
    • getClass() - 객체의 런타임 클래스 반환
    • clone() - 객체의 복제본 반환
    • notify, notifyAll(), wait() - 스레드 동기화 관련 메소드
  • Object 클래스의 메서드는 서브클래스에서 오버라이드해 다양한 구현을 제공한다.

ref

Tistory_inpa

profile
"개발자는 해결사이자 발견자이다✨" - Michael C. Feathers

0개의 댓글