1. 부모 클래스의 참조변수가 부모 클래스 본인의 객체뿐만 아니라, 자식 클래스의 인스턴스(객체)도 참조할 수 있음 2. 자식 클래스의 인스턴스(객체)를 자식 클래스 타입의 참조 변수 뿐만 아니라, 부모 클래스 타입의 참조 변수로 참조할 수 있음
참조변수의 다형성
클래스들 사이에서 반드시 상속 관계가 전제할 것
다형성을 위하여 부모 클래스 타입의 참조변수로 자식 클래스 타입의 인스턴스(객체)를 참조할 수 있도록 함
반대의 경우, 자식 클래스 타입의 참조 변수로는 부모 클래스 타입의 인스턴스를 참조할 수 없음
그 이유는, 참조 변수가 사용할 수 있는 멤버의 개수가 실제 인스턴스의 멤버(부모 클래스 인스턴스)보다 많기 때문
자식 클래스는 부모의 멤버를 상속 받기 때문에, 사용할 수 있는 멤버의 개수가 부모 클래스보다 같거나 더 많음
class Parent { }
class Child extends Parent { }
public class Main {
public static void main(String [] args) {
Parent pa = new Parent(); // 허용
Child ch = new Child(); // 허용
// 다형성 이용
Parent pa2 = new Child(); // 허용
// 자식 타입의 참조변수로, 부모 클래스 타입의 인스턴스 참조 X
Child ch2 = new Parant(); // 오류 발생, (X)
}
}
예제
class Animal {
String category;
}
class Cat extends Animal { // Animal 클래스(상위 클래스)를 상속
String name;
int age;
}
public class AnimalTest {
public static void main(String [] args) {
// 상위 클래스 타입의 참조변수(a)가 그 상위 클래스의 객체를 가리킴
Animal a = new Animal();
// 다형성: 상위 클래스 타입의 참조변수(b)가 하위 클래스의 객체를 가리킬 수 있음
Animal b = (Animal)new Cat();
Animal b = new Cat(); // (형변환타입) 생략 가능
}
}
자바의 참조형 캐스팅(형 변환)
캐스팅(casting) 타입을 변환하는 것, 형 변환
상속 관계의 클래스 간에 형 변환하기
상속 관계의 클래스는 부모 클래스와 자식 클래스로 구분
자바의 상속 관계에 있는 부모와 자식 클래스 간에는만 서로 형 변환이 가능함
기본형 타입들끼리 서로 형 변환이 가능한 것과 같이
참조형 타입들끼리도 형 변환이 가능
자식 클래스 타입에서 부모 클래스 타입으로의 타입 변환은, 형 변환 생략 가능(업캐스팅)
부모 클래스 타입에서 자식 클래스 타입으로의 타입 변환은, 반드시 명시(다운캐스팅)
클래스는 참조형 타입(reference 타입)이므로, 부모클래스와 자식 클래스 간의 형 변환을 '참조형 캐스팅'이라고 함
참조형 캐스팅의 종류
업캐스팅
다운 캐스팅
자식 클래스의 객체는 부모 클래스를 상속하고 있기 때문에, 자신의 멤버는 물론이고 부모의 멤버(변수, 메서드 등)도 모두 사용할 수 있음
반면 부모 클래스의 객체는 자식 클래스의 멤버(변수, 메서드 등)를 갖지 않으므로, 사용할 수 없음
업캐스팅(upcasting)
개념
클래스의 상속 구조에서
부모 클래스 타입의 참조 변수가 자식 클래스 인스턴스를 가리킬 수 있는 능력
즉, 자식 클래스 타입이 부모 클래스 타입으로 변환되는 것(타입의 변환)
특징
자식 클래스 타입을 부모 클래스 타입으로 변환된다는(업캐스팅) 것은, 멤버의 개수가 감소한다는 것
즉, 자식 클래스에만 있는 변수와 메서드는 실행하지 못한다는 것
= 부모 클래스 타입으로 타입이 변환되었기 때문에 자식 클래스의 멤버 사용 불가
부모 타입의 참조 변수로 부모 클래스에 있는 변수와 메서드만 접근할 수 있음
업캐스팅을 하고 나서, 메서드를 호출할 때
만일 자식 클래스에서 부모 클래스의 메서드를 오버라이딩 한 메서드(@override)가 있는 경우
부모 클래스의 메서드가 아닌 오버라이딩 된 메서드가 실행됨
업캐스팅을 하는 이유가 뭘까?
공통적으로 사용하려고 하는 부분을 만들어서 관리하기 위함
즉 상속 관계에서 자식 클래스의 개수에 상관 없이, 하나의 인스턴스(부모 클래스 하나)로묶어서 관리할 수 있음
상속 관계를 맺어 부모 클래스 타입으로 업캐스팅을 하면,하나의 타입(부모 타입)으로 관리할 수 있음
업캐스팅 형식
// () 괄호에 변환할 타입을 작성하여 형 변환
Animal a = (Animal) new Cat(); // Animal타입으로 형 변환
// 업캐스팅은 자동 형변환 가능, () 괄호 생략 가능
Animal a = new Cat();
Cat 클래스는 Anumal클래스를 상속받은 클래스이므로
Cat은 Cat 타입이면서 동시에 Animal 타입이기도 함
따라서, Cat 클래로 인스턴스를 생성할 때, 이 인스턴스의 타입을 Animal형으로 형 변환을 할 수 있음
원래의 Cat 인스턴스의 타입은 Cat인데
new Cat을 Animal형으로 변경할 수 있음. 즉, (Animal) new Cat;
참조변수 a가 가리키는 것은
참조 변수 클래스형에 기반한 멤버변수와 메서드에 접근할 수 있음
즉, Animal 클래스의 멤버변수와 메서드만 접근 가능
업캐스팅 시에 주의할 점
사용할 수 있는 멤버(멤버변수, 메서드)의 개수가 감소하여, 멤버에 대한 접근이 제한됨
자식 클래스 타입을 부모 클래스 타입으로 형 변환을 하는 것이기 때문에, 자식 타입을 마음대로 사용할 수 있을 것 같지만, 업캐스팅된 상태에서 자식 타입에 마음대로 접근할 수 없음
[ 이유 ] 부모를 상속하여 부모의 멤버(멤버변수, 메서드)는 물론 본인의 멤버까지 사용할 수 있었던 자식 클래스에서, 부모 클래스로 업캐스팅(형변환)을 하였으니 당연히 멤버 개수가 감소하게 됨. 즉, 부모 클래스로 형 변환을 하였으니, 부모의 멤버(멤버변수, 메서드)만 사용할 수 있게 됨
[ 원칙 ] 업캐스팅이 된 상태에서 부모 클래스 타입의 참조변수로, 자식 클래스의 필드나 메서드에 접근할 수 없음
[ 다운캐스팅 ] 자식 클래스의 필드나 메서드에 접근하기 위해서는, 다시 자식 클래스 타입으로 다운캐스팅 필요
업캐스팅 시에 자식 클래스의 멤버에 대한 접근이 제한
1. 업캐스팅이 된 상태에서 메서드 호출 시에, 부모 클래스에서 오버라이딩 된 메서드를 먼저 호출
부모 클래스에 bark() 메서드가 있고, 자식 클래스에서 오버라이딩 된 메서드(같은 메서드명을 가지는 bark() 메서드)가 있을 때, 업캐스팅이 된 상태에서 bark() 메서드를 호출하면 부모와 자식 클래스의 bark 메서드 중에 어떤 메서드가 호출이 될까?
✔️ 원칙적으로는, 부모 클래스 타입의 참조변수로는 자식 클래스의 메서드를 호출할 수 없음️ ✔️ 하지만 업캐스팅 된 상태에서는, 하위 클래스에서 오버라이딩 된 메서드가 먼저 호출이 됨