상속 관계의 클래스 객체 형변환
- 부모 : Account 클래스
- 필드 : accountNo, ownerName, balance
- 메소드 : deposit(), cardNo()
- 자식 : CheckingAccount 클래스
- 필드 : cardNo
- 메소드 : pay()
조건
obj1 은 Account의 타입 객체로 생성한다.
obj2 은 CheckingAccount 타입 객체로 생성한다.
obj 는 Account 타입 객체이지만 CheckingAccount 타입으로 형변환한다.
잘못된 형변환 예제를 고쳐서 캐스팅 형변환이 가능하도록 한다.
- 스택영역 : obj, obj1, obj2 (참조형 변수들)
- 힙 영역 : obj, obj1, obj2 참조형 변수들 클래스 타입의 객체 주소
출력 결과
지불이 불가능합니다.
예제 코드
Account.java
부모 클래스1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
public class Account { String accountNo; //계좌번호 String ownerName; //예금주 이름 int balance; //잔액 //Account() { //} Account(String accountNo, String ownerName, int balance) { this.accountNo = accountNo; this.ownerName = ownerName; this.balance = balance; } void deposit(int amount) { balance += amount; } int withdraw(int amount) throws Exception { if (balance < amount) throw new Exception("잔액이 부족합니다."); balance -= amount; return amount; } }
CheckingAccount.java
자식 클래스1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
public class CheckingAccount extends Account { String cardNo; //직불카드 번호 필드 //CheckingAccount() { //super() : 부모 클래스 디폴트 생성자 자동 호출 // super(); //this(); //} CheckingAccount(String accountNo, String ownerName, int balance, String cardNo) { // 생성자 //super(); super(accountNo, ownerName, balance); //명시적으로 부모 클래스 생성자 호출 //this.accountNo = accountNo; //this.ownerName = ownerName; //this.balance = balance; this.cardNo = cardNo; } int pay(String cardNo, int amount) throws Exception { if (!cardNo.equals(this.cardNo) || (balance < amount)) throw new Exception("지불이 불가능합니다."); return withdraw(amount); } }
RefTypeExample6.java
잘못된 캐스팅 형변환 실행코드1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
public class RefTypeExample6 { public static void main(String args[]) { Account obj = new CheckingAccount("111-22-33333333", "홍길동", 10, "4444-5555-6666-7777"); CheckingAccount obj2 = obj; try { int amount = obj2.pay("4444-5555-6666-7777", 47000); System.out.println("인출액: " + amount); System.out.println("카드번호: " + obj2.cardNo); } catch (Exception e) { System.out.println(e.getMessage()); } } }
부모에게 없는 필드에 접근을 요청하기 때문에 자식객체는 부모클래스에 있는 필드와 메소드에 접근할 수 없다.
작성 코드
RefTypeExample6.java
캐스팅 형변환을 실행한 실행 코드1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
public class RefTypeExample6 { public static void main(String args[]) { Account obj1 = new Account("AAA", "AA", 10); Account obj = new CheckingAccount("111-22-33333333", "홍길동", 10, "4444-5555-6666-7777"); CheckingAccount obj2 = (CheckingAccount)obj; //강제 형변환, 대입이 가능해진다. try { int amount = obj2.pay("4444-5555-6666-7777", 47000); System.out.println("인출액: " + amount); System.out.println("카드번호: " + obj2.cardNo); } catch (Exception e) { System.out.println(e.getMessage()); } } }
- obj 객체가 주소 100번지의 CheckingAccount 클래스를 가리키는 Account 클래스 타입 객체이다.
(ojb 객체 주소 : 100번지) - 그러면 CheckingAccount클래스에서 Account에 생성된 필드와 메소드만(상속된 것만) 접근이 가능하다.
- 캐스팅 형변환으로 CheckingAccount 클래스 타입인 obj2 객체가 obj의 100번지 주소를 가르키고 있다고 알려주기 때문에 접근이 가능하다.
(ojb2 객체 주소 : 100번지)
- obj 객체가 주소 100번지의 CheckingAccount 클래스를 가리키는 Account 클래스 타입 객체이다.
문법적인 오류는 없지만 실행오류가 나는 실행코드
RefTypeExample6.java
문법적인 오류는 없지만 try 실행시 obj2.pay를 수행하지 못한다1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
public class RefTypeExample6 { public static void main(String args[]) { Account obj1 = new Account("AAA", "AA", 10); //CheckingAccount 형변환 타입이 아니다 CheckingAccount obj2 = (CheckingAccount)obj1; //오류 Account obj = new CheckingAccount("111-22-33333333", "홍길동", 10, "4444-5555-6666-7777"); // CheckingAccount obj2 = (CheckingAccount)obj; //강제 형변환, 대입이 가능해진다. try { int amount = obj2.pay("4444-5555-6666-7777", 47000); System.out.println("인출액: " + amount); System.out.println("카드번호: " + obj2.cardNo); } catch (Exception e) { System.out.println(e.getMessage()); } } }
- Account 타입의 obj1 객체가 200번지의 Account 클래스를 가리키고 있다.
(obj1 객체주소 : 200번지) - CheckingAccount 타입의 obj2 객체도 똑같이 200번지의 Account 클래스를 가리키게 된다.
(obj2 객체주소 : 200번지)
- Account 타입의 obj1 객체가 200번지의 Account 클래스를 가리키고 있다.
오류 원인
CheckingAccount obj2 = (CheckingAccount) obj1;
- 문법적인 형식은 잘못이 없지만 obj1 이 가리키고 있는 객체 앞에 있는 형변환의 타입(new Account(“AAA”, “AA”, 10);)이 아니면 오류가 난다.
- Account 타입의 obj1 객체를 변환한다고 CheckingAccount 타입으로 바뀌진 않는다.
Account 타입의 obj1이 Account(new Account(“AAA”, “AA”, 10);) 객체정보만 가지고 있어서
CheckingAccount에 있는 정보를 접근할 수 없기 때문에 형변환이 안 된다. - 즉 obj2는 CheckingAccount의 필드와 메소드 정보를 가지고 있으나
obj1이 가리키는 Account 클래스에는 CheckingAccount클래스의 필드와 메소드(ex : cardNo())가 없기 때문에
허용이 되지 않아 사용하지 못 한다.
🌞 정보 : 공부 기록용 블로그입니다. 오타나 내용 오류가 있을 경우 알려주시면 감사하겠습니다.
댓글남기기