모래블로그

3. Object 다형성 본문

카테고리 없음

3. Object 다형성

별모래 2024. 7. 17. 07:17
728x90

 

3. Object 다형성

 

다형성(polymorphism)

다형성이란 하나의 객체가 여러 가지 타입을 가질 수 있는 것을 의미한다.

Java 에서는 한 타입의 참조 변수를 통해 여러 타입의 객체를 참조할 수 있도록 하는 것이다.

즉, 상위 클래스(부모)타입의 참조 변수를 통해서 하위 클래스(자식)의 객체를 참조할 수 있도록 허용하여, 상위 클래스가 동일한 메시지로 하위 클래스들이 서로 다른 동작을 할 수 있도록 한다.

출처: https://ittrue.tistory.com/132 [IT is True:티스토리]

 

object 다형성

Object모든 클래스의 부모 클래스이므로 모든 객체를 참조할 수 있다.

 

 

Car 클래스

public class Car {
  public void move() {
    System.out.println("자동차 이동");
  }
}
 

 

Dog 클래스

public class Dog {
  public void sound() {
    System.out.println("멍멍");
  }
}
 

CarDog는 서로 관련이 없는 클래스고, 둘 다 부모가 없으므로 Object를 자동으로 상속 받는다.

 

main

public class ObjectPolyExample1 {
  public static void main(String[] args) {
    Dog dog = new Dog();
    Car car = new Car();

    action(dog);
    action(car);
  }

  private static void action(Object obj) {
    // obj.sound(); // 컴파일 오류, Object는 sound()가 없다.
    // obj.move(); // 컴파일 오류, Object는 move()가 없다.

    // 객체에 맞는 다운캐스팅 필요
    if (obj instanceof Dog dog) {
      dog.sound();
    } else if (obj instanceof Car car) {
      car.move();
    }
  }
}
 

실행 결과

 

Object는 모든 타입의 부모이고, 부모는 자식을 담을 수 있으므로 앞의 코드들을 아래처럼 변경도 가능하다.

// 앞의 이 코드들을
Dog dog = new Dog();
Car car = new Car();

// 아래로 변경 가능
Object dog = new Dog(); // Dog -> Object
OBject car = new Car(); // Car -> Object
 

 

항상 무언가를 찾을 때는 위로 올라가야하는데,

Object는 이미 최상위이므로 내려갈 수 없어서 자기자신 밖에 모르므로 sound, move가 무엇인지 알 수 없다.

그러므로 다음과 같이 호출은 불가능하다.

 private static void action(Object obj) {
     obj.sound(); // 컴파일 오류, Object는 sound()가 없다.
     obj.move(); // 컴파일 오류, Object는 move()가 없다.
}
 

 

Object 다형성의 장점

action(Object obj) 메서드를 분석해보면, 이 메서드는 Object 타입의 매개변수를 사용한다.

Object는 모든 객체의 부모이므로 어떤 객체든지 인자로 전달할 수 있다.

action(dog) // main에서 dog 전달
void action(Object obj = dog) // Object는 자식인 Dog 타입을 참조할 수 있다

action(car) // main에서 dog 전달
void action(Object obj = car) // Object는 자식인 Car 타입을 참조할 수 있다
 

 

Object 다형성의 한계

action(dog) // main에서 dog 전달
private static void action(Object obj) {
    obj.sound(); // 컴파일 오류, Object는 sound()가 없다.
}
 

action() 메서드 안에서 obj.sound() 를 호출하면 오류가 발생한다.

그 이유는 매개변수인 objObject 타입이기 때문이다.

Object에는 sound() 메서드가 없다.

 

 

 

obj.sound() 호출

  1. obj.sound()를 호출한다.
  2. objObject 타입이므로 Object 타입에서 sound()를 찾는다.
  3. Object에서 sound()를 찾을 수 없다. Object는 최종 부모이기 때문에 더는 올라가서 찾을 수 없으므로 오류가 발생한다.

 

Dog 인스턴스의 sound()를 호출하기 위해서는 다음처럼 다운캐스팅을 해야한다.

if (obj instanceof Dog dog) {
    dog.sound();
}
 

 

 

 

1. Object obj의 참조값을 Dog dog로 다운캐스팅 하면서 전달한다.

2. dog.sound()를 호출하면 Dog 타입에서 sound()를 찾아서 호출한다.

 

 

다운 캐스팅(DownCasting)

업캐스팅은 자식 클래스가 부모 클래스 타입으로 캐스팅 되는 것라면,

다운캐스팅은 거꾸로 부모 클래스가 자식 클래스 타입으로 캐스팅 되는 것이다.

그렇다고 단순히 업캐스팅의 반대 개념이 아니며, 다운캐스팅의 목적은 업캐스팅한 객체를 다시 자식 클래스 타입의 객체로 되돌리는데 목적을 둔다. (복구)

출처: https://inpa.tistory.com/entry/JAVA-☕-업캐스팅-다운캐스팅-한방-이해하기#다운_캐스팅downcasting [Inpa Dev 👨‍💻:티스토리]

 

 

Object 를 활용한 다형성의 한계

  • Object모든 객체를 대상으로 다형적 참조를 할 수 있다
    • 쉽게 이야기해서 Object는 모든 객체의 부모이므로 모든 객체를 담을 수 있다.
  • Object를 통해 전달 받은 객체를 호출하려면 각 객체에 맞는 다운캐스팅 과정이 필요하다
    • Object가 모든 메서드를 알고 있는 것이 아님

 

다형성을 제대로 활용하려면 다형적 참조 + 메서드 오버라이딩함께 사용해야 한다.

그런 면에서 Object를 사용한 다형성에는 한계가 있다.

 

Object는 모든 객체의 부모이므로 모든 객체를 대상으로 다형적 참조를 할 수 있다.

Object 본인이 보유한 toString() 같은 메서드는 당연히 자식 클래스에서 오버라이딩 할 수 있지만,

위의 예시처럼 ObjectDog.sound(), Car.move()와 같은 다른 객체의 메서드가 정의되어 있는 것이 아니므로 메서드 오버라이딩을 활용할 수 없다. 따라서 각 객체의 기능을 호출하려면 다운캐스팅을 해야 한다.

 

∴ 다형적 참조는 가능하지만, 메서드 오버라이딩이 안되기 때문에 다형성을 활용하기에는 한계가 있다.

 

그렇다면 언제 Object를 활용하면 좋을까 ?

 


4. Object 배열

 

Object 배열

Object는 모든 타입의 객체를 담을 수 있고, Object[] 는 세상의 모든 객체를 담을 수 있는 배열을 만들 수 있다.

public class ObjectPolyExample2 {
  public static void main(String[] args) {
    Dog dog = new Dog();
    Car car = new Car();
    Object object = new Object(); // Object 인스턴스도 만들 수 있다.

    Object[] objects = {dog, car, object};
    size(objects);
  }
  private static void size(Object[] objects) {
    System.out.println("전달된 객체의 수는: " + objects.length);
  }
}
 

 

실행 결과

 

 

 

 

Object[] objects = {dog, car, object};
// 쉽게 풀어서 설명하면 다음과 같다.
Object objects[0] = new Dog();
Object objects[1] = new Car();
Object objects[2] = new Object();
 

 

 

 

objects 배열에 [0]에 Dog, [1]에 Car, [2]에 Object가 담겨있다.

 

size() 메서드

size(Object[] objects) 메서드는 배열에 담긴 객체의 수를 세는 역할을 담당한다.

이 메서드는 Object 타입만 사용한다.

Object 타입의 배열은 세상의 모든 객체를 담을 수 있기 때문에, 새로운 클래스가 추가되거나 변경되어도 이 메서드를 수정하지 않아도 된다.

 

 

Object가 없다면 ?

만약 Object와 같은 개념이 없다면 ?

  • void action(Object obj)과 같이 모든 객체를 받을 수 있는 메서드를 만들 수 없다.
  • Object[] objects와 같이 모든 객체를 저장할 수 있는 배열을 만들 수 없다.

 

물론 Object가 없다고 하더라도, 직접 MyObject와 같은 클래스를 만들고 모든 클래스에서 직접 정의한 MyObject를 상속 받으면 된다.

하지만 하나의 프로젝트를 넘어서 전세계 모든 개발자들이 비슷한 클래스를 만들 것이고, 서로 호환되지 않는 수 많은 XxxObject 들이 넘쳐나게 될 것이다.

 

 

 

참고 강의 : 김영한 - 실전 자바 중급 1편

 

728x90