언어/Java

클래스의 타입 변환과 다형성

O_oz 2023. 8. 27. 12:56
반응형

다형성 : 하나의 타입에 여러 객체를 대입함으로써 다양한 기능을 이용할 수 있도록 함

    - 부모 타입에 모든 자식 객체를 대입 가능 > 객체의 부품화가 가능함

타입 변환 : 데이터 타입을 다른 데이터 타입으로 변환하는 행위 (기본 타입 변환 설명 글)

    - 클래스 타입의 변환은 상속 관계에 있는 클래스 사이에서 발생하며 자식 타입은 부모 타입으로 자동 타입 변환이 가능

 

1. 자동 타입 변환 (promotion) : 프로그램 실행 도중 자동적으로 타입 변환이 일어나는 것

부모클래스 변수 = 자식클래스타입;

    - 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급 가능

class Animal { ... }
class Cat { ... }

Cat cat = new Cat();	// Cat 객체 참조
Animal animal1 = cat;	// Cat 객체 참조
Animal animal2 = new Cat();

cat == animal1		// true

    - 자동 타입 변환한 두 변수는 동일한 객체를 참조

    - 바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환 가능

public class Parent {
    public void method1() {
    	System.out.println("Parent-method1()");
    }
    public void method2() {
        System.out.println("Parent-method2()");
    }	
}
public class Child extends Parent {
    @Override
    public void method2() {
        System.out.println("Child-method2()");
    }
    public void method3() {
        System.out.println("Child-method3()");
    }
}

 

public class Example {
    public static void main(String[] args) {
        Child child = new Child();
        
        Parent parent = child;
        parent.method1();		// Parent-method1()
        parent.method2();		// Child-method2()
        // parent.method3();	호출 불가능
    }
}

    - 부모 타입으로 자동 타입 변환된 후에는 부모 클래스에 선언된 필드와 메소드만 접근 가능

    - 변수는 자식 객체를 참조하지만 접근 가능한 멤버는 부모 클래스 멤버만 가능

    - 메소드가 자식 클래스에서 오버라이딩 되었다면 자식 클래스의 메소드가 대신 호출됨

 

2. 필드의 다형성

다형성 : 동일한 타입을 사용하지만 다양한 결과가 나오는 성질

    - 필드의 값을 다양화함으로써 실행 결과가 다르게 나오도록 구현

    - 필드 타입은 변함 없지만, 실행 도중 어떤 객체를 필드로 저장하느냐에 따라 실행 결과가 달라질 수 있음

    - 프로그램은 수많은 객체들의 연결이고 각 객체들은 자신의 역할을 수행하는데, 이러한 객체는 언제든지 다른 객체로 교체될 수 있어야 함

    - 상속, 오버라이딩, 타입 변환을 적절히 사용하여 다형성을 구현

 

3. 하나의 배열로 객체 관리

    - 동일한 타입의 값들은 배열로 관리하는 것이 유리

    - 부모 타입의 배열에 자식 객체를 대입하면 자동 타입 변환이 발생하므로 문제 없음

    - 상속 관계에 있는 객체들은 배열로 관리하면 제어문에서 혜택을 봄

 

public class Tire {
    // 필드
    public int maxRotation;		// 최대 회전수 (타이어 수명)
    public int accumulatedRotation;	// 누적 회전수
    public String location;		// 타이어의 위치
    
    // 생성자
    public Tire(String location, int maxRotation){
        this.location = location;
        this.maxRotation = maxRotation;
    }
    
    // 메소드
    public boolean roll() {
    	++accumulatedRotation;	// 누적 회전수 1 증가
        if (accumulatedRotation<maxRotation) {
            System.out.println(location + "Tire 남은 회전수 : " + (maxRotation-accumulatedRotation) + "회");
            return true;
        } else {
            System.out.println("*** " + location + " Tire 펑크 ***");
            return false;
        }
    }
}
public class Car {
    // 필드
    Tire[] tires = {new Tire("앞왼쪽", 6), new Tire("앞오른쪽", 2), new Tire("뒤왼쪽", 3), new Tire("뒤오른쪽", 4)};
    
    // 생성자
    
    // 메소드
    int[] run() {
        System.out.println("자동차 주행");
        
        int[] result = {0, 0, 0, 0};	// 펑크난 타이어 번호를 저장
        
        for (int i = 0; i < tires.length; i++) {
            if (tires[i].roll() == false) {
                stop();
                result[i] = i+1;
            }
        }
        return result;
    }
    
    void stop() {
    	System.out.println("자동차 멈춤");	
    }
}
public class HankookTire extends Tire {
    // 필드
    
    // 생성자
    public HankookTire(String location, int maxRotation) {
        super(location, maxRotation);
    }
    
    // 메소드
    @Override
    public boolean roll() {
    	++accumulatedRotation;	// 누적 회전수 1 증가
        if (accumulatedRotation < maxRotation) {
            System.out.println(location + "HankookTire 남은 회전수 : " + (maxRotation-accumulatedRotation) + "회");
            return true;
        } else {
            System.out.println("*** " + location + " HankookTire 펑크 ***");
            return false;
        }
    }
}
public class Example {
    public static void main(String[] args) {
        Car car = new Car();
        
        for (int i = 1; i <= 5; i++) {
            int[] problemLocations = car.run();
            
            // 펑크난 타이어가 존재하면 해당 타이어를 한국타이어로 교체
            for (int problemLocation : problemLocations) {
            	if (problemLocation != 0) {
            	    System.out.println(car.tires[problemLocation - 1].location + " HankookTire로 교체");
            	    car.tires[problemLocation - 1] = new HankookTire(car.tires[problemLocation - 1].location, 15);
            	}
            }
            System.out.println("-----------------------------------");
        }
    }
}

    - 교제에는 앞선 타이어부터 문제가 생기면 남은 타이어가 회전하지 않는 문제가 존재해서 앞선 타이어에서 문제가 발생하더라도 남은 타이어 모두 1회씩 회전하도록 예제를 변경함

 

4. 매개 변수의 다형성

    - 자동 타입 변혼은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생

    - 메소드를 호출할 때, 매개값을 다양화하기 위해 매개 변수에 자식 타입 객체를 지정할 수도 있음

    - 매개 변수이 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로 사용 가능

    - 자식 객체가 부모의 메소드를 오버라이딩했다면 메소드 내부에서 오버라이딩된 메소드를 호출함으로써 메소드의 실행 결과가 다양해짐

 

5. 강제 타입 변환 (Casting) : 자식 타입이 부모 타입으로 자동 변환한 후, 다시 자식 타입으로 변환하는 것

자식클래스 변수 = (자식클래스) 부모타입으로변환된자식타입변수;

    - 부모 타입으로 자동 타입 변환된 자식 타입 객체는 부모 타입의 필드와 메소드만 사용 가능하기 때문에, 자식 타입의 필드와 메소드를 꼭 사용해야한다면 강제 타입 변환을 사용해 다시 자식 타입으로 변환해야 함

 

6. 객체 타입 확인 (instanceof)

    - 어떤 객체가 어떤 클래스의 인스턴스인지 확인할 수 있는 연산자 / 매개값의 타입을 조사할 때 주로 사용

boolean result = 객체 instanceof 타입

    - 좌항엔 객체, 우항엔 타입이 오며, 좌항이 우항의 타입으로 객체가 생성되었다면 true

    - 강제 타입 변환을 하기 전 instanceof 연산자로 변환시킬 타입의 객체인지 조사하는 과정이 필요

반응형

'언어 > Java' 카테고리의 다른 글

중첩 클래스와 인터페이스  (0) 2023.08.29
인터페이스  (1) 2023.08.27
메소드 재정의 (오버라이딩)  (0) 2023.08.24
상속  (0) 2023.08.24
어노테이션  (0) 2023.08.24