객체 형변환

치로·2024년 7월 19일

객체 형변환

1. 객체 형변환

  • Jave 기본 유형의 데이터들처럼 객체 참조 변수의 경우에도 형변환(casting)이 이루어진다.
  • 서로 다른 클래스 유형으로부터 나온 객체 참조변수들 간의 대입에는 일정한 규칙이 있음
    Parent p = new Child();
  • 왼쪽 항(Parent)과 오른쪽 항(Child)의 객체 유형이 서로 다른 경우, 두 유형이 서로 상속 관계에 있고 왼쪽 객체가 오른쪽 객체의 상위 클래스인 경우에만 암묵적 형변환이 일어난다
  • 하위 클래스에서 상위 클래스 유형으로 할당하는 것은 가능하나, 그 경우에는 명시적 형변환을 해야함

2. 객체 간의 암묵적 형변환

A a1 = new B(); // 가능
A a2 = new X(); // 가능

A a3 = new C(); // 가능
A a4 = new Y(); // 가능

B b1 = new C(); // 가능
X x1 = new Y();  // 가능

C c = new C(); // 가능
B b2 = c; // 가능

Y y = new Y(); // 가능
X x2 = y; // 가능

3. 암묵적 형변환과 메서드 오버라이드

  • 암묵적 형변환은 부모를 상속받는 자식 객체의 기능을 부모에게 물려받은 기능만 사용하도록 제한
  • 그러므로 암묵적 형변환이 발생하게 되면 오버라이드 기능만 사용 가능하고, 추가적으로 구현한 기능은 사용할 수 없음
  • 주의할 점은 기능의 제한이지 기능의 변경은 아님
  • 상속 관계의 객체를 부모 형태로 변환하면 클래스의 종류를 구분하지 않고 일관된 기능을 호출할 수 있고, 객체가 상위 클래스 형태로 형변환 되더라도 Override된 자신의 기능은 잃지 않음
    Unit u1 = new Army();
    Unit u2 = new Navy();
    Unit u3 = new AirForce();
    u1.attack();
    u2.attack();
    u3.attack();
  • 하지만, 추가적으로 구현한 기능은 사용할 수 없게 되므로, 원래의 기능을 다시 사용할 수 있는 방법이 필요해 졌다.

4. 명시적 형변환

  • 부모 클래스이 객체를 자식 클래스 형태로 변환하는 것
  • 형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해 주어야 함
    ChildClass child = (ChildClass)parent;

5. 명시적 형변환의 조건

  • 객체가 최초 생성될 때 자식 클래스 형태로 생성되고, 부모 형태로 암묵적 형변환이 된 상태를 다시 원래의 자식 클래스 형태로 되돌릴 경우만 가능
    CClass child1 = new CClass();
    PClass parent = child1; // 암묵적 형변환
    CClass child2 = (CClass)parent; // 명시적
  • 가능한 경우 : new로 할당된 원본 클래스로 되돌아가는 경우에만 가능

Army army1 = new Army();
Unit u = army1;
Army army2 = (Army)u;

Unit u =new Navy();
Navy navy = (Navy)u;

  • 불가능 : 최초 객체 생성이 부모 형태로 만들어진 경우
    Unit u = new Unit();
    Army army = (Army)u;

  • 불가능 : 최초 생성된 것과 다른 형식으로 변환하는 것을 불가능
    Army army = new Army();
    Unit u = army;
    Navy navy = (Navy)u;

  • 위의 두 경우 모두 문법적인 오류는 없기 때문에 이클립스에서는 에러를 검출하지 못함
    하지만 프로그램을 실행시켰을 경우에는 에러가 발생

📌 예시 코드 📌

package boxing;

class Hello {
	public void say() {
		System.out.println("Hello");
	}
}

class Korean extends Hello {
	@Override
	public void say() {
		System.out.println("안녕하세요");
	}
	public void talk() {
		System.out.println("또 만났군요");
	}
}

public class Main01 {

	public static void main(String[] args) {
		Hello k = new Korean(); //암묵적 형변환
		k.say();
		// Hello에게 정의된 기능이 아니므로 에러
		// k.talk();
	}

}
package boxing;

public class AirForce extends Unit{
	
	public AirForce(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 공중 공격 실행");
	}
	
	public void bombing() {
		System.out.println(super.getName() + " >> 폭격");
	}
}
package boxing;

public class Army extends Unit{

	public Army(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 지상 공격 실행!");
	}
	
	public void tank() {
		System.out.println(super.getName() + " >> 탱크 공격!");
	}
} 
package boxing;

public class Navy extends Unit{
	
	public Navy(String name) {
		super(name);
	}
	
	@Override
	public void attack () {
		super.attack();
		System.out.println(super.getName() + " >> 어뢰 발사!");
		System.out.println(super.getName() + " >> 지상 상륙");
	}
		
	public void nucleus() {
		System.out.println(super.getName() + " >> 탱크 공격!");
	}
}
package boxing;

public class Unit {
	private String name;

	public Unit(String name) {
		super();
		this.name = name;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	
	public void attack () {
		System.out.println(this.name + " >> 공격 준비");
	}

}
package boxing;

public class Main02 {

	public static void main(String[] args) {
		AirForce af = new AirForce("공군");
		Navy nv = new Navy("해군");
		Army am = new Army("육군");
		
		// 각각의 객체는 자신들의 공유 기능을 사용할 수 있음
		af.bombing();
		nv.nucleus();
		am.tank();
		
		System.out.println("-----------");
		
		// 1. 각각의 af, nv, am이라는 객체를 temp1, temp2, temp3라는 이름의 상위 객체로 암묵적 형변환
		// 2. temp1, temp2, temp3객체로 attack()이라는 메서드를 각각 호출
		Unit temp1 = af;
		Unit temp2 = nv;
		Unit temp3 = am;
		
		af.attack();
		nv.attack();
		am.attack();
		System.out.println("-----------");
		
		//상위 클래스 형태로 형변환이 되면, 자신들의 독립 기능은 사용하지 못함 
//		temp1.bombing();
//		temp2.nucleus();
//		temp3.tank();
		
		//명시적 형변환 다시 원래의 기능을 되돌리기 위해서는 하위 클래스 형태로 명시적 형변환이 필요함
		AirForce re1 = (AirForce)temp1;
		Navy re2 = (Navy)temp2;
		Army re3 = (Army)temp3;
		
		re1.bombing();
		re2.nucleus();
		re3.tank();
		
	}

}

0개의 댓글