자바에서 캐스팅(형변환)은 타입을 변환하는 것을 뜻한다.
기본 자료형에서도 등호를 중심으로 항상 왼쪽과 오른쪽 자료형이 일치해야 하는데
만일 자료형이 다를 경우에 컴파일러가 자동으로 타입을 변환해주던가 사용자가 직접 변환해줘야 한다.
이 포스트에서는 상속 관계에 있는 부모, 자식 클래스간에 형변환인 업캐스팅, 다운캐스팅에 대한 내용과 왜 사용하는지 작성하였다.
업 캐스팅
자식 클래스가 부모 클래스 타입으로 형변환 되는 것
Java에서 자식 클래스는 부모 클래스의 모든 특성을 상속받는다.
class Person{
String name;
public Person(String name) {
this.name = name;
}
}
class Student extends Person{
String age;
public Student(String name) {
super(name);
}
}
public class CastingTest {
public static void main(String[] args) {
// student 참조변수를 이용하면 age, name에 접근 가능하다.
Student student = new Student("AshShine");
// person 참조변수를 이용하면 Student 객체의 멤버 중에서 Person 클래스의 멤버에만 접근이 가능하다.
Person person = student; // "업 캐스팅"
// Person person = new Person("test");
person.name = "JYJY";
System.out.println(person.name);
// person.age = "26"; // 컴파일 오류 ~!
}
}
Person person = (Person) student 를 통해 업 캐스팅이 되었다.
Person 타입이므로 자신의 클래스에 속한 멤버와 메서드만 접근할 수 있다.
업 캐스팅을 하였더니 객체내의(student 객체)모든 멤버와 메서드에 접근할 수 없다. (person.age="26"에 오류 발생)
업 캐스팅은 명시적 타입 캐스팅을 선언하지 않아도 객체 앞에 묵시적으로 형변환을 수행한다.
Student student = new Student();
Person person = (Person) student;
업 캐스팅을 수행하는 이유..
하나의 인스턴스(슈퍼클래스 즉, 부모클래스)로 서브클래스들을 전부 관리 할 수 있어서이다.
즉, 슈퍼클래스로 관리하면 자바의 다형성(메서드를 각각 다른형태로 사용)을 이용해 슈퍼클래스를 여러가지 클래스로 만들 수 있다.
다음 예제를 참고하자.
class Food{
public void eat(){
System.out.println("Food eat");
}
}
class HardBar extends Food{
@Override
public void eat(){
System.out.println("HardBar eat");
}
}
class Soju extends Food{
@Override
public void eat(){
System.out.println("Soju eat");
}
}
class Person {
public void personEat(Food somethingFood) {
somethingFood.eat();
}
}
public class CastingTest{
public static void main(String[] args){
Person person = new Person();
Food foodVal1 = new HardBar(); // 업캐스팅!
Food foodVal2 = new Soju(); // 업캐스팅!
person.personEat(foodVal1); //HardBar eat
person.personEat(foodVal2); //Soju eat
}
}
업 캐스팅을 통해 각 클래스들의 메서드를 호출할 때 음식이 하드바이던 소주던 업캐스딩된 참조변수를 넘겨주면(여기서 foodVal1, foodVal2) 사람 클래스는 타입검사 없이 메서드를 호출 할 수 있다.
여기서 만약 업캐스팅을 사용하지 않으면 어떻게 될까?
각 음식의 객체를 메서드로 호출한다고 할 때 음식이 하드바인지, 소주인지 검사하는 조건문을 넣고 각 조건에 맞는 객체의 메서드를 호출해야 한다.
업캐스팅을 쓰지않고 Person, CastingTest 클래스만 변경하였다.
//만약 업캐스팅을 안쓰면??
class Person {
public void personEat(Food somethingFood) {
if (somethingFood instanceof HardBar) {
somethingFood.eat();
} else if (somethingFood instanceof Soju) {
somethingFood.eat();
}
// 클래스가 많다면 이를 판별하기 위한 조건문을 길게 쓸 수 밖에 없다.
}
}
public class CastingTest{
public static void main(String[] args){
Person person = new Person();
HardBar hardBar = new HardBar();
Soju soju = new Soju();
person.personEat(hardBar);//HardBar eat
person.personEat(soju); //Soju eat
}
}
클래스가 계속 생성되면 어떤 객체가 어떤 타입인지 판별하기 위해 조건문을 길게 써야한다.
다운 캐스팅
다운 캐스팅은 업캐스팅 했을 때 잃어버린 고유 특성을 복구하는 것을 말한다. (업캐스팅을 undo한것)
class Person{
String name;
public Person(String name){
this.name = name;
}
void abc(){}
}
class Student extends Person {
String grade;
public Student(String name){
super(name);
}
void bcd(){}
}
public class CastingTest {
public static void main(String[] args) {
Person person = new Student("testName"); // 업캐스팅
// person.bcd(); ERROR!
Student student = (Student) person; // 다운캐스팅
student.name = "han";
student.grade = "A";
student.abc();
student.bcd();
}
}
다운캐스팅은 업캐스팅과 다르게 명시적으로 타입을 지정해야 한다.
instanceof
다운캐스팅에서 객체의 타입을 구분하기위해 instanceof연산자를 사용하였다.
래퍼런스 변수가 가리키는 객체의 타입이 어떤 것인지 구분하기 어려울 때 유용하다.
package TypeCasting_3;
class A{}
class B extends A{}
public class Main {
public static void main(String[] args) {
// instanceof
A aa = new A();
A ab = new B();
System.out.println(aa instanceof A);
System.out.println(ab instanceof A);
System.out.println(aa instanceof B);
System.out.println(ab instanceof B);
if(aa instanceof B){
B b = (B) aa;
System.out.println("aa를 B로 캐스팅 했습니다");
} else {
System.out.println("aa는 B 타입으로 캐스팅이 불가능 합니다");
}
if(aa instanceof B){
B b = (B) ab;
System.out.println("ab를 B로 캐스팅했습니다.");
} else{
System.out.println("ab는 B타입으로 캐스팅이 불가능 합니다");
}
if("안녕" instanceof String) {
System.out.println("안녕 은 String 클래스 입니다.");
}
}
}
결과
true
true
false
true
aa는 B 타입으로 캐스팅이 불가능 합니다
ab는 B타입으로 캐스팅이 불가능 합니다
안녕 은 String 클래스 입니다.
instanceof는 참조형 타입에만 사용할 수 있다.
if("AshShine" instanceof String) {
// String 타입이므 true
}
// 컴파일 오류! primitive type은 안된다.
if(3 instanceof int) {
}
참고한 곳
'Language > Java' 카테고리의 다른 글
[Java] 익명 클래스, 익명 이너 클래스 (0) | 2022.04.03 |
---|---|
[Java] Interface(인터페이스) VS Abstract Class(추상 클래스) 차이점, 정리 (0) | 2022.04.03 |
[Java] 메소드 오버라이딩 / 메소드 오버로딩 (0) | 2021.07.15 |
[Java] 클래스, 객체, 인스턴스, 메소드 란? (0) | 2021.07.14 |
[Java] 상속(Inheritance) (0) | 2021.07.14 |