java 기본 유형의 데이터들처럼 객체 참조변수의 경우에도 형변환(casting)이 이루어진다.
서로 다른 클래스 유형으로부터 나온 객체 참조변수들 간의 대입에는 일정한 규칙이 있다.
Parent parent = new Child();
위의 대입연산에서 왼쪽 항(부모, Parent)과 오른쪽 항(자식, Child)의 객체 유형이 서로 다른 경우, 두 유형이 서로 상속관계에 있고 왼쪽 객체가 오른쪽 객체의 상위 클래스인 경우에만 암묵적인 변환이 일어난다.
하위 클래스에서 상위클래스 유형으로 할당하는 것은 가능하나 그 반대의 경우에는 명시적 형 변환을 해야한다.
암묵적 형변환 가능한 경우
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;
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
안녕하세요.
안녕하세요.
또 만났군요.
Unit u1 = army;
Unit u2 = navy;
Unit u3 = airforce;
u1.attack();
u2.attack();
u3.attack();
// 부모 클래스가 가지고 있는 기능이 아니므로 에러
u1.tank();
u2.nucleus();
u3.bumbing();
부모 클래스의 객체를 자식 클래스 형태로 변환하는 것
형변환을 위해서는 다음과 같이 변환할 클래스 이름을 명시적으로 지정해 주어야 한다.
ChildClass child = (ChildClass)parent;
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
육군 >> 탱크공격
해군 >> 핵미사일
공군 >> 폭격
---------------------------
육군 >>> 공격준비!!!
육군 >> 지상공격 실행
해군 >>> 공격준비!!!
해군 >> 어뢰발사
해군 >> 지상 상륙
공군 >>> 공격준비!!!
공군 >> 이륙
공군 >> 공중공격 실행
----------------------
육군 >> 탱크공격
해군 >> 핵미사일
공군 >> 폭격