JAVA - 객체 형변환

박종휘·2022년 10월 28일
0

JAVA - 국비

목록 보기
19/29
post-thumbnail
post-custom-banner

1. 객체 형변환

1-1. 객체 형변환

  • java 기본 유형의 데이터들처럼 객체 참조변수의 경우에도 형변환(casting)이 이루어진다.

  • 서로 다른 클래스 유형으로부터 나온 객체 참조변수들 간의 대입에는 일정한 규칙이 있다.

    		Parent parent = new Child();
  • 위의 대입연산에서 왼쪽 항(부모, Parent)과 오른쪽 항(자식, Child)의 객체 유형이 서로 다른 경우, 두 유형이 서로 상속관계에 있고 왼쪽 객체가 오른쪽 객체의 상위 클래스인 경우에만 암묵적인 변환이 일어난다.

  • 하위 클래스에서 상위클래스 유형으로 할당하는 것은 가능하나 그 반대의 경우에는 명시적 형 변환을 해야한다.

1-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;

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

  • 암묵적 형변환은 부모를 상속받는 자식 객체의 기능을 부모에게 물려받은 기능만 사용하도록 제한한다.
  • 그러므로 암묵적 형변환이 발생하게 되면 오버라이드된 기능만 사용 가능하고, 추가적으로 구현한 기능은 사용할 수 없다.
  • 주의할 점은 기능의 제한이지 기능의 변경은 아니라는 것이다.
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 h = new Korean();
		h.say();
		// talk는 Hello 클래스에 정의된 기능이 아니므로 에러
		// h.talk();
		
		Korean k = new Korean();
		k.say();
		k.talk();
	}
}
result

안녕하세요.
안녕하세요.
또 만났군요.

1-4. 객체 형변환

	Unit u1 = army;
    Unit u2 = navy;
    Unit u3 = airforce;
    
    u1.attack();
    u2.attack();
    u3.attack();
    
    // 부모 클래스가 가지고 있는 기능이 아니므로 에러
    u1.tank();
    u2.nucleus();
    u3.bumbing();
  • 상속관계의 객체를 부모 형태로 변환하면, 클래스의 종류를 구분하지 않고 일괄된 기능을 호출 할 수 있다. 객체가 상위클래스의 형태로 형변환 되더라도 Override된 자신의 기능은 잃지 않는다.
  • 하지만, 추가적으로 구현한 기능은 사용할 수 없게 되므로 원래의 기능을 다시 사용 할 수 있는 방법이 필요해졌다.

1-5. 명시적 형변환

  • 부모 클래스의 객체를 자식 클래스 형태로 변환하는 것

  • 형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해 주어야 한다.

    		ChildClass child = (ChildClass)parent;

1-6. 명시적 형변환의 조건

  • 객체가 최초로 생성될 때 자식 클래스 형태로 생성되고, 부모 형태로 암묵적 형변환이 된 상태를 다시 원래의 자식 클래스 형태로 되돌릴 경우에만 가능해진다.

ChildClass child1 = new ChildClass();
ParentClass parent = child1;				// 암묵적 형변환
ChildClass child2 = (ChildClass)parent;		// 명시적 형변환

// - 가능한 경우
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;

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 AirForce extends Unit{

	public AirForce(String name) {
		super(name);
	}
	
	@Override
	public void attack() {
		super.attack();
		System.out.println( this.getName() + " >> 이륙" );
		System.out.println( this.getName() + " >> 공중공격 실행" );
	}
	
	public void bombing() {
		System.out.println(
			this.getName() + " >> 폭격");
	}
}

------------------------------------------------------------

package boxing;

public class Army extends Unit {

	// 부모 클래스의 생성자를 강제 호출하기 위한 생성자
	public Army(String name) {
		super(name);
	}

	// 공격의 형태를 육군에 맞게 변경하지만,
	// 부모 클래스가 가지고 있는 공격 준비 기능을
	// super 키워드를 통해 보전
	@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( this.getName() + " >> 어뢰발사" );
		System.out.println( this.getName() + " >> 지상 상륙" );
	}
	
	public void nucleus() {
		System.out.println( 
			this.getName() + " >> 핵미사일");
	}
}

------------------------------------------------------------

package boxing;

public class Main01 {

	public static void main(String[] args) {
		// 1시 40분
		// army, navy, airforce로 각각의 객체생성
		Army am = new Army("육군");
		Navy nv = new Navy("해군");
		AirForce af = new AirForce("공군");
		
		// 그 각각의 객체의 고유 기능을 사용
		am.tank();
		nv.nucleus();
		af.bombing();
		
		System.out.println("---------------------------");
		
		// 상위 객체 형태로 암묵적 형변환
		// 상위 클래스의 객체로 암묵적 형변환이 이루어지면 Override된 기능만 사용 가능
		// 추가적으로 확장된 기능들은 사용할 수 없도록 잠김 상태가 된다.
		// 모든 객체는 자신의 상위 형태로 암묵적 형변환 가능
		Unit temp1 = am;
		Unit temp2 = nv;
		Unit temp3 = af;
		
		// 형변환이 되더라도 상속받거나 재정의한(Override)
		// 자신들의 기본 특성들은 그대로 유지
		temp1.attack();
		temp2.attack();
		temp3.attack();
		
		// 상위 클래스 형태로 형변환이 되면, 자신들의 독립 기능은
		// 사용하지 못한다.
//		temp1.tank();
//		temp2.nucleus();
//		temp3.bombing();
		
		System.out.println("----------------------");
		
		// 다시 원래의 기능을 되돌리기 위해서는
		// 하위 클래스 형태로 명시적 형변환이 필요함
        // -> 독립적인 기능 사용 가능
		Army re1 = (Army)temp1;
		Navy re2 = (Navy)temp2;
		AirForce re3 = (AirForce)temp3;
		
		re1.tank();
		re2.nucleus();
		re3.bombing();
	}
}
result

육군 >> 탱크공격
해군 >> 핵미사일
공군 >> 폭격
---------------------------
육군 >>> 공격준비!!! 
육군 >> 지상공격 실행
해군 >>> 공격준비!!! 
해군 >> 어뢰발사
해군 >> 지상 상륙
공군 >>> 공격준비!!! 
공군 >> 이륙
공군 >> 공중공격 실행
----------------------
육군 >> 탱크공격
해군 >> 핵미사일
공군 >> 폭격
profile
개린이의 개발 고수되기 작전!
post-custom-banner

0개의 댓글