javaboiii의 JAVA/JAVA 요약정리(멘토씨리즈)

JAVA -11) 다형성과 타입 변환

javaboiii 2024. 7. 22. 12:21

JAVA

1. 클래스에서의 타입 변환

타입 변환은 타입을 다른 타입으로 변환하는 것으로 자바에서는 다음과 같이 두 가지의 대표적인 타입 변환이 있습니다.

  • 자료형(타입) 변환
  • 클래스의 객체 타입 변환

클래스의 타입 변환도 마찬가지로 자동 형 변환과 강제 형 변환이 있습니다. 단, 자료형에 비해 타입 변환이 가능한

범위가 상당히 좁습니다. 클래스의 타입 변환은 서로 상속 관계에 있는 클래스 사에서만 변환할 수 있습니다.

클래스의 자동 타입 변환

자료형에서의 자동 형 변환과 마찬가지로 개발자가 직접 명시하지 않아도 자동으로 타입 변환이 일어나는 것을

'클래스 자동 타입 변환'이라고 부릅니다. 클래스 자동 타입 변환은 상속 관계에 있는 자식 클래스의 객체를 부모 타입의

객체로 변환하는 것을 말합니다. 클래스의 자동 타입 변환을 구현하는 방법을 알아보겠습니다.

 

자식 객체를 만들면서 바로 부모 타입으로 변환할 때는 다음과 같이 구현합니다.

부모 클래스(타입) 객체 변수 = new 자식 클래스();

 

만들어진 자식 객체를 부모 타입으로 변환할 때는 다음과 같이 구현합니다.

부모 클래스(타입) = 자식 객체;

타입을 변환한다고 객체가 바뀌는 것이 아니라 객체는 보존되고 사용만 부모 객체처럼 사용합니다.

또한 클래스 자동 타입 변환은 자식 타입에서 부모 타입 방향으로만 가능합니다.

따라서 부모 타입을 자식 타입으로 변환하려고 하면 오류가 발생합니다.

 

자동 타입 변환은 반드시 상속 관계에 있는 자식 클래스의 객체를 부모 타입으로 변환할 때 적용할 수 있습니다.

1차 상속 관계가 아니더라도 상위 계층의 타입으로 변환할 수 있습니다. 하지만 같은 상위 계층을 가지고 있더라도

타입 변환을 시도하려는 두 클래스 간의 상속 관계가 없다면 타입 변환은 불가능합니다.

 

프로그래밍에서 타입 변환은 상속 관계의 개념에서 자연스레 뻗어 나온 특징으로 볼 수 있습니다.

 

자료형 변환에서는 자동 형 변환 시에도 명시적으로 변혼을 작성하는 것을 추천하지만 클래스의 타입 변환에서는

명시하는 것이 불가능한 것은 아니지만 일반적으로 자식 타입에서 부모 타입으로 변환하는 경우에는 

타입 형태를 작성하지 않습니다.

이는 반대 방향으로의(부모타입 -> 자식 타입)타입 변환인 강제 타입 변환과 가시적인 차이점을 두기 위함이기도 합니다.

 

타입을 부모 타입으로 변환하는 객체는, 더 이상 자신의 클래스에 부모 클래스와 별개로 추가한 멤버들을 사용할 수 없으며

부모클래스에 선언된 멤버(필드와 메서드)들만 사용할 수 있습니다.

단, 부모 클래스의 메서드를 오버라이딩한 메서드의 경우에는 자식 객체의 것을 호출 할 수 있습니다.

 

클래스의 강제 타입 변환

자식 타입에서 부모 타입으로 자동 타입 변환을 했지만 자식 클래스의 멤버들에게 접근하고 싶을 때가 생길 수 있습니다.

자바의 규약으로 부모 타입에서는 자식 클래스의 멤버에 접근할 수 없으므로 이러한 경우 자식타입으로 타입을 변경해서 접근할 수 있도록 제공하고 있습니다

이를 '클래스 강제 타입 변환'이라고 부릅니다. 자식 객체가 부모 타입으로 자동 타입 변환을 한 후, 다시 자식 타입으로 변환하는 것을 말합니다.

 

클래스 타입 변환에서 강제 타입 변환은 자동 타입 변환과는 달리, 개발자가 직접 명시해야만 타입 변환을 할 수 있습니다.

자식 타입을 부모 타입으로 변환할 때는 별도 명시가 없어도 프로그램이 실행되면서 자동으로 타입을 변환해 주지만,

부모 타입에서 자식 타입응로 변환하려면 우리는 반드시 변환하고자 하는 타입 형태를 직접 작성해야 합니다.

 

일회성으로 타입 변환이 필요할 때는, 다음과 같이 사용할 수 있습니다.

((자식타입)부모타입).메서드();

 

자식 클래스의 멤버들에 대한 접근이 여러 번 필요한 경우에는 다음과 같이 자식 타입 변수에 담아서 사용하기도 합니다.

자식 타입 변수 = (자식타입) 부모타입;

자식 타입으로 다시 타입 변환을 해줌으로써 부모 타입에서는 사용하지 못했던 자식의 멤버들을 모두 사용할 수 있게 됩니다. 단, 모든 부모 타입 객체를 자식 타입으로 변환할 수 있는 것은 아닙니다. 반드시 부모 타입으로 자동 타입 변환되었던 자식 객체를 다시 자식 타입으로 변환할 때만 강제 타입 변환을 사용할 수 있습니다.

2. 다형성(Polymorphism)

다형성은 객체 지향 프로그래밍의 대표적인 특징 중 하나로, 하나의 타입으로 다양한 객체를 사용할 수 있는 것을 의미합니다. 자바에서는 클래스 타입 변환을 통해, 부모 클래스의 타입을 하나로 여러 가지 자식 객체들을 참조하여 사용함으로써

다형성을 구현할 수 있습니다. 결과적으로 클래스 타입 변환이 존해하는 이유는 다형성을 구현하기 위함이라고도 할 수 있습니다. 하지만 타입 변환은 다형성을 구현하는 방법의 하나일 뿐, 혼자 다형성을 완전히 구현해낼 수는 없습니다.

다형성을 구현하는 데 큰 역할을 하는 다음 세 가지 특징이 힘을 합쳐야 합니다.

상속 + 메서드 오버라이딩 + 클래스 타입 변환

다형성을 활용할 수 있는 방법은 말 그대로 다양합니다 객체가 특정 클래스의 필드가 되면서, 하나의 부품처럼 사용될 수도 있습니다. 이때, 부품을 교체할 일이 생긴다면 다형성을 구현함으로써 코드 수정을 최소화할 수 있습니다.

 

객체를 변경하기 위해서 여러 가지 코드를 수정하는 것은 상당히 위험도가 높은 작업입니다. 실무에서의 프로그램은 코드의 양이 많아지고, 수많은 객체가 서로 얽혀서 복잡한 로직으로 구현되어 있습니다. 이런 경우, 어떻게 하면 수정을 최소화하고 실수를 줄일 수 있을까 생각해 봐야 합니다.

 

객체를 필드로 가지는 클래스에서 객체 타입을 부모 클래스 타입으로 수정하면 간단하게 다형성을 적용한 코드가 됩니다.

3. instanceof 연산자

부모 타입으로 타입이 변환되어 저장된 변수는 안에 어떤 객체가 담겨 있는지 직접 확인해 보지 않는 이상 내부 객체를

알기 쉽지 않습니다.

객체 instanceof 타입(클래스명)

instanceof 연산자의 특징은 다음과 같습니다.

  • instanceof 기준으로 왼쪽 객체가 생성될 때 오른쪽 타입으로 생성되었는지 확인하는 연산자입니다.
  • 맞으면, true, 아니면 false를 반환하며 만약 null을 가리키고 있으면 false를 반환합니다.

4. 오버로딩과 오버라이딩

객체 지향 프로그래밍에서 다형성을 얘기할 때 빼놓을 수 없는 것이 바로 오버로딩과 오버라이딩 입니다.

비슷한 기능을 하고 중복되는 구현이 필요하지만 오버로딩과 오버라이딩을 적절히 사용할 수 있다면

중복이 없는 최소한의 코드로 원하는 기능을 모두 구현해낼 수 있습니다.

응용문제

1. 다음 코드는 컴파일 에러가 발생합니다. 컴파일 에러가 발생하는 곳을 모두 찾아 수정해 보세요.

package section11;

class Car{}
class Bus extends Car{}
class SchoolBus extends Bus{}

class OpenCar extends Car{}
class SportsCar extends OpenCar{}

public class PRACTICE_11_01{
	public static void main(String[] args){
    	Car c1 = new SchoolBus();
        Bus b1 = new Bus();
        SchoolBus sb = new Car();
        
  	Car c2 = new OpenCar();
        OpenCar oc = new SportsCar();
        Bus b3 = new OpenCar();	// 오류
        Bus b4 = new SportsCar(); //오류
    }
}

주석으로 표시된 라인에서 오류가 발생하고 이유는 OpenCar클래스와 SportsCar 클래스는 Bus 클래스와 같은 상위 계층

클래스 Car와 상속 관계는 맞지만, Bus클래스와 직접적인 상속 관계가 아니므로 자동 타입 변환을 할 수 없습니다.

수정
package section11;

class Car{}
class Bus extends Car{}
class SchoolBus extends Bus{}

class OpenCar extends Car{}
class SportsCar extends OpenCar{}

public class PRACTICE_11_01{
	public static void main(String[] args){
    	Car c1 = new SchoolBus();
        Bus b1 = new Bus();
        SchoolBus sb = new Car();
        
  	Car c2 = new OpenCar();
        OpenCar oc = new SportsCar();
        Bus b3 = new SchoolBus();
        Bus b4 = new Bus();
    }
}

2. 다음 설명에 해당하는 용어는 무엇입니까 ?

부모 클래스에게 상속받은 메서드를 재정의하여 자식 클래스용 메서드를 구현하고 자식 객체를 통해 메서드를 호출할

때는 부모의 메서드가 아니라 자식의 메서드가 호출된다.

 

① 오버라이딩

② 오버로딩

③ 오버플로우

정답 : ①

3. 다음과 같은 결과가 나오도록 아래 클래스를 구현해 주세요

class Speaker

class RedSpeaker

class BlueSpeaker

package section11;

class Person{
	Speaker speaker;
    
    Person(Speaker speaker){
    	this.speaker = speaker;
    }
    
    void turnOn(){
    	System.out.println(speaker.getName()+" 이 켜졌습니다.");
    }
}
public class PRACTICE_11_03{
	public static void main(Stirng[] args){
    	Speaker s1 = new RedSpeaker();
        Person p1 = new Person();
        p1.turnOn();
        
        Speaker s2 = new BlueSpeaker();
        Person p2 = new Person();
        p2.turnOn();
    }
}

실행결과 : 
빨간 스피커가 켜졌습니다
파란 스피커가 켜졌습니다.

class Speaker {
    String getName() {
        return "스피커";
    }
}

class RedSpeaker extends Speaker {
    @Override
    String getName() {
        return "빨간 스피커";
    }
}

class BlueSpeaker extends Speaker {
    @Override
    String getName() {
        return "파란 스피커";
    }
}
class Person{
	Speaker speaker;
    
    Person(Speaker speaker){
    	this.speaker = speaker;
    }
    
    void turnOn(){
    	System.out.println(speaker.getName()+" 이 켜졌습니다.");
    }
}
public class PRACTICE_11_03{
	public static void main(Stirng[] args){
    	Speaker s1 = new RedSpeaker();
        Person p1 = new Person();
        p1.turnOn();
        
        Speaker s2 = new BlueSpeaker();
        Person p2 = new Person();
        p2.turnOn();
    }
}

'javaboiii의 JAVA > JAVA 요약정리(멘토씨리즈)' 카테고리의 다른 글

JAVA -13) 내부 클래스  (2) 2024.07.24
JAVA -12) 추상 클래스와 인터페이스  (4) 2024.07.23
JAVA -10)상속  (0) 2024.07.21
JAVA -9)생성자  (2) 2024.07.20
JAVA -8) 메서드(Method)  (0) 2024.07.19