형변환에는 값형 형변환과 참조형 형변환이 있다.
값형 형변환은 boolean을 제외한 값형끼리의 형변환이며, integer형을 character형으로 바꾸고 double형을 float형으로 바꾸는 작업 등을 한다. 따지고보면 character도 숫자형(아스키코드)이기 때문에 값형 형변환은 숫자형끼리의 형변환이라고 이해할 수 있다.
값형 형변환에 대해서는 위 글의 연산자를 설명할 때, 오버플로우와 대입연산자 부분에서 언급했다.
그렇다면 참조형 형변환은 무엇인가?
💡참조형 형변환
참조형 형변환은 자바에서 참조형끼리의 형변환과 클래스끼리의 형변환을 의미한다.
직계 상속 관계에 있는 클래스들 간에만 형변환이 가능하다는 특징이 있으며, 업캐스팅과 다운캐스팅 두 가지 유형이 있다.
업캐스팅 (Up Casting)
Parent p1;
Child c1;
c1 = new Child(); // 원본
p1 = c1; // 업캐스팅 발생
업캐스팅은 암시적인 형변환으로, 부모 클래스의 타입을 자식 클래스의 타입으로 변환하는 것을 의미한다.
이때 형변환을 명시적으로 표시하지 않아도 자동으로 이루어지며, 부모 클래스 타입으로 선언된 변수에 자식 클래스 객체를 할당할 수 있다.
업캐스팅은 안전한 형변환으로 간주되며 항상 성공한다.
다운캐스팅 (Down Casting)
Parent p3;
Child c4;
c4 = (Child)p3; // 다운캐스팅
다운캐스팅은 명시적인 형변환으로, 자식 클래스의 타입을 부모 클래스의 타입으로 변환하는 것을 의미한다.
이때 형변환을 명시적으로 표시해야 하며, 컴파일러는 이를 검증하지 않는다.
다운캐스팅은 런타임 시 형변환의 유효성을 체크하며, 원래 객체가 해당 자식 클래스 타입으로 생성되었을 경우에만 성공한다. 만약 그렇지 않을 경우 ClassCastException 예외가 발생하게 된다.
💡참조형 형변환의 활용
package com.test.java.obj.casting;
public class Ex_Casting {
public static void main(String[] args) {
Printer[] ps = new Printer[8]; // 프린트라는 타입을 넣을 수 있는 객체(껍데기)를 8개 생성
// 서로 다른 클래스의 객체를 하나의 배열에 생성
ps[0] = new LG500();
ps[1] = new HP600();
// 업캐스팅
for (int i = 0; i < ps.length; i++) {
if (i < 5) {
ps[i] = new LG500(); // LG500 프린터 5개
} else {
ps[i] = new HP600(); // HP600 프린터 3개
}
}
// 다운캐스팅
for (int i = 0; i < ps.length; i++) {
ps[i].print();
if (ps[i] instanceof LG500) {
((LG500)ps[i]).selfTest();
} else if (ps[i] instanceof HP600){
((HP600)ps[i]).cleaning();
}
}
}
}
interface Printer {
void print();
void powerOn();
void powerOff();
}
class LG500 implements Printer {
private String type;
private int price;
public void print() {
System.out.printf("%s 방식 출력\n", this.type);
}
public void selfTest() {
System.out.println("자가 점검 진행\n");
}
@Override
public void powerOn() {
System.out.println("프린터 전원 ON\n");
}
@Override
public void powerOff() {
System.out.println("프린터 전원 OFF\n");
}
}
class HP600 implements Printer {
private String color;
private int price;
public void powerOn() {
System.out.println("프린터 전원 켜짐\n");
}
public void powerOff() {
System.out.println("프린터 전원 꺼짐\n");
}
public void cleaning() {
System.out.println("헤더 청소 진행\n");
}
@Override
public void print() {
System.out.printf("출력 진행\n");
}
}
8개의 프린터 중에 5개는 LG500 프린터이고, 3개는 HP600 프린터라고 하자.
LG500과 HP600 프린터는 공통적으로 프린트를 할 수 있는 기능이 있지만, 각각의 기능도 구현되어 있다.
LG500은 selfTest() 기능이 있으며, HP600은 cleaning() 기능이 개별적으로 있다.
업캐스팅은 서로 다른 형들끼리 하나의 배열에 넣기 위해서 사용한다.
그런데 자식들이 가지고 있는 개개인의 기능들은 사용할 수가 없다. 이때 다운캐스팅을 쓰는 것이다!
괄호로 묶어 다운캐스팅으로 다시 형변환을 해주면 클래스 각각의 기능인 selfTest를 쓸 수 있다.