본문 바로가기
Study/JAVA

[Java] 7-5. 다형성(polymorphism)

by jeongwle 2022. 9. 5.
728x90
반응형

 

다형성(polymorphism)

1. 다형성이란?

객체지향개념에서 다형성이란 여러가지 형태를 가질 수 있는 능력을 말한다. 자바에서는 한 타입의 참조변수로 여러 타입의 객체를 참조할 수 있도록 하여 다형성을 프로그램적으로 구현하였다. 구체적으로 말하면 상위 클래스 타입의 참조변수로 하위 클래스 인스턴스를 참조할 수 있도록 하였다는 말이다.

class Tv {
  boolean power;
  int channel;
  
  void power() { power = !power; }
  void channelUp() { ++channel; }
  void channelDown() { --channel; }
}

class CaptionTv extends Tv {
  String texst;
  void caption() { ... }
}

Tv t = new CaptionTv(); // O 가능
CaptionTv ct = new Tv(); // X 불가​

위의 경우 Tv타입의 참조변수로 CaptionTv클래스의 인스턴스를 참조하도록 했다. 하지만 참조변수 t로 CaptionTv인스턴스의 모든 멤버를 사용할 수는 없고 Tv클래스의 멤버들만 사용할 수가 있다. 참조변수가 사용할 수 있는 멤버의 개수는 인스턴스의 멤버 개수와 같거나 적어야 한다. 그렇다면 인스턴스의 타입과 일치하는 참조변수를 사용하면 인스턴스의 멤버들을 모두 사용할 수 있는데 왜 상위 클래스 타입의 참조변수로 인스턴스의 일부 멤버만을 사용하도록 할까 라는 의문이 들 것이다. 이에 대한 답은 앞으로 배우게 된다. 지금은 상위 클래스 타입의 참조변수로 하위 클래스의 인스턴스를 참조할 수 있다는 사실과 그 차이에 대해서만 이해하고 넘어가자.

상위 클래스 타입의 참조변수로 하위 클래스의 인스턴스를 참조할 수 있다.
하위 클래스 타입의 참조변수로 상위 클래스의 인스턴스를 참조할 수 없다.​

 

2. 참조변수의 형변환

서로 상속관계에 있는 경우 하위 클래스 타입의 참조변수를 상위 클래스 타입의 참조변수로, 상위 클래스 타입의 참조변수를 하위 클래스 타입의 참조변수로 형변환이 가능하다. 기본형 변수의 형변환에서 작은 자료형에서 큰 자료형의 형변환은 생략이 가능하듯이 참조형 변수의 형변환에서 하위 클래스 타입의 참조변수를 상위 클래스 타입으로 형변환 할 경우 형변환을 생략할 수 있다.

하위 클래스 타입 -> 상위 클래스 타입(Up-casting) : 형변환 생략가능
상위 클래스 타입 -> 하위 클래스 타입(Down-casting) : 형변환 생략불가​

형변환 하고자 할 때 괄호() 안에 변환하고자 하는 타입의 이름(클래스명)을 적어주면 된다.

형변환은 참조변수의 타입을 변환하는 것이지 인스턴스를 변환하는 것은 아니다. 참조변수의 형변환은 인스턴스에 아무런 영향을 주지 않는다. 참조변수의 형변환을 통해서 참조하고 있는 인스턴스에서 사용할 수 있는 멤버의 범위(개수)를 조절하는 것 뿐이다. 그리고 하위 클래스로의 형변환은 생략할 수 없고 형변환을 수행하기 전에 instanceof연산자를 사용해 참조변수가 참조하고 있는 실제 인스턴스의 타입을 확인하는 것이 안전하다.

 

3. instanceof연산자

참조변수가 참조하고 있는 인스턴스의 실제 타입을 알아보기 위해 instanceof연산자를 사용한다. 주로 조건문에 사용되고 instanceof의 왼쪽에는 참조변수를, 오른쪽에는 타입(클래스 명)이 피연산자로 위치한다. 그 결과값은 true 또는 false이다.
어떤 타입에 대한 instanceof연산자의 결과가 true라는 것은 검사한 타입으로 형변환이 가능하다는 것을 뜻한다.​

 

4. 참조변수와 인스턴스의 연결

상위 클래스에 선언된 멤버변수와 같은 이름의 인스턴스변수를 하위 클래스에 중복으로 정의했을 때, 상위 클래스 타입의 참조변수로 하위 클래스 인스턴스를 참조하는 경우와 하위 클래스 타입의 참조변수로 하위 클래스 인스턴스를 참조하는 경우는 서로 다른 결과를 얻는다. 메서드의 경우 참조변수의 타입에 관계없이 항상 실제 인스턴스의 메서드가 호출되지만 멤버변수의 경우 참조 변수의 타입에 따라 달라진다.

멤버변수가 상위 클래스, 하위 클래스에 중복으로 정의되었을 경우 상위 클래스 타입의 참조변수를 사용하면 상위 클래스에 선언된 멤버변수가 사용되고, 하위 클래스 타입의 참조변수를 사용하면 하위 클래스에 선언된 멤버변수가 사용된다. 중복으로 정의되지 않은 경우엔 차이가 없다.

public class SuperTest {
    public static void main(String[] args) {
        Super s = new Sub();
        Sub s2 = new Sub();

        System.out.println("s.x = " + s.x); // 10
        System.out.println("s2.x = " + s2.x); // 20
    }
}

class Super {
    int x = 10;

    void method() {
        System.out.println("Parent method!!");
    }
}

class Sub extends Super {
    int x = 20;

    void method() {
        System.out.println("Child method!!");
    }
}​

 

5. 매개변수의 다형성

참조변수의 다형적인 특징은 메서드의 매개변수에도 적용된다. 예시를 살펴보자

public class PolyArgumentTest {
    public static void main(String[] args) {
        Buyer b = new Buyer();
        Product television = new Television();
        Product computer = new Computer();

        b.buy(television);
        b.buy(computer);

        System.out.println("b.money = " + b.money); // 700
        System.out.println("b.bonusPoint = " + b.bonusPoint); // 30
    }
}

class Product {
    int price;
    int bonusPoint;

    Product(int price) {
        this.price = price;
        bonusPoint = price / 10;
    }
}

class Television extends Product {
    Television () {
        super(100);
    }

    public String toString() {
        return "Television";
    }
}

class Computer extends Product {
    Computer() {
        super(200);
    }

    public String toString() {
        return "Computer";
    }
}

class Buyer {
    int money = 1000;
    int bonusPoint = 0;

    void buy(Product product) {
        if (money < product.price) {
            System.out.println("잔액이 부족합니다.");
            return;
        }
        money -= product.price;
        this.bonusPoint += product.bonusPoint;
        System.out.println(product + " 구입 완료");
    }
}​

Buyer클래스의 buy메서드를 살펴보면 매개변수 인자로 Product를 받고 있다. 만약 다형성을 적용하지 않는다면 Computer타입의 매개변수를 받는 buy메서드, Television타입의 매개변수를 받는 buy메서드 등 물품이 늘어날 때마다 구현해야할 buy메서드가 늘어나게 된다. 하지만 예시처럼 Product클래스의 매개변수를 받으면 price와 bonusPoint를 사용할 수 있기 때문에 하나의 메서드로 충분하게 된다.

 

6. 여러 종류의 객체를 배열로 다루기

상위 클래스 타입의 참조변수로 하위 클래스 타입의 객체를 참조하는 것이 가능하므로, Product클래스가 Tv, Computer, Audio클래스의 상위 클래스 일 때 다음과 같이 할 수 있는 것을 배웠다.

Product p1 = new Tv();
Product p2 = new Computer();
Product p3 = new Audio();​

위의 코드를 Product타입의 참조변수 배열로 처리하면 아래와 같다.
Product[] p = new Product[3];
p[0] = new Tv();
p[1] = new Computer();
p[2] = new Audio();​

이처럼 상위 클래스 타입의 참조변수 배열을 사옹하면, 공통의 상위 클래스를 가진 서로 다른 종류의 객체를 배열로 묶어서 다룰 수 있다.

 

 

* Vector 클래스

책에서 물건을 담을 배열로 Vector 클래스를 소개하고 있어서 간단하게 알아보고 가자.

메서드 / 생성자 설 명
Vector() 10개의 객체를 저장할 수 있는 Vector인스턴스를 생성한다.
10개 이상의 인스턴스가 저장되면 자동으로 크기가 증가된다.
boolean add(Object o) Vector에 객체를 추가한다. 추가에 성공하면 결과값으로 true, 실패하면 false를 반환한다.
boolean remove(Object o) Vector에 저장되어 있는 객체를 제거한다. 제거에 성공하면 true, 실패하면 false를 반환한다.
boolean isEmpty() Vector가 비어있는지 검사한다. 비어있으면 true, 아니면 false를 반환한다.
Object get(int index) 지정된 위치(index)의 객체를 반환한다. 반환타입이 Object타입이므로 적절한 타입으로의 형변환이 필요하다.
int size() Vector에 저장된 객체의 개수를 반환한다.
728x90
반응형

'Study > JAVA' 카테고리의 다른 글

[Java] 7-7. 인터페이스(interface)  (0) 2022.09.06
[Java] 7-6. 추상클래스(abstract class)  (0) 2022.09.06
[Java] 7-4. 제어자(modifier)  (0) 2022.09.05
[Java] 7-3. package와 import  (0) 2022.09.05
[Java] 7-2. 오버라이딩(overriding)  (0) 2022.09.03

댓글