JAVA/java 이론

[자바JAVA]다형성/ 업캐스팅, 다운캐스팅/instanceof연산자/ 형변환

자바칩 프라푸치노 2020. 10. 22. 16:39

이 포스팅은 아래의 내용을 포함하고 있습니다.

1. 다형성이란

2. 참조변수의 형변환

3. instanceof 연산자

4. 예제


1. 다형성이란?

- 조상타입의 참조변수로 자손타입의 객체를 다룰 수 있는 것

 

- 다룰 수 있는 멤버 개수가 다르다( 예제에서 확인)

 

- 조상타입의 참조변수로 자손타입의 인스턴스를 참조할 수 있지만 자손타입의 참조변수로 조상타입의 인스턴스를 참조할 수 없음

 

- 메서드를 오버라이딩한 경우

자손클래스의 메서드가 호출됨

 

2. 참조변수의 형변환

- 서로 상속, 구현관계에 있는 타입간 형변환이 가능하다.

자손-> 조상 형변환 (업캐스팅): 형변환 생략 가능

조상-> 자손 형변환 (다운캐스팅): 형변환 생략 가능

 

(예제)

<조상클래스>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package sec01_exam;
//조상클래스 멤버갯수: 4개
public class Car {
 
    String color;
    int door;
    //운전하는 기능
    void drive() {
        System.out.println("drive, Brrr~");
    }
    //멈추는 기능
    void stop() {
        System.out.println("stop!!");
    }
}
 
cs

<자손클래스>

1
2
3
4
5
6
7
8
9
10
11
package sec01_exam;
//extends는 상속관계(직접적 관계), Ambulance멤버의 갯수는 5개
public class Ambulance extends Car{
//사이렌 기능
    void siren()
    {
        System.out.println("삐융삐융~");
    }
    
}
 
cs

<자손클래스>

1
2
3
4
5
6
7
8
9
package sec01_exam;
//extends는 상속관계(직접적 관계), FireEngine클래스의 멤버는 몇개? 5개
public class FireEngine extends Car{
 
    void water() {
        System.out.println("water!!");
    }
}
 
cs

<실행클래스>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package sec01_exam;
 
public class CastingEx {
 
    public static void main(String[] args) {
 
 
        Car car = null;
        FireEngine fe = new FireEngine();
        FireEngine fe2 = null;
        
        fe.water();
        //업캐스팅(자손-> 조상) 형변환 생략 가능, 다룰 수 있는 멤버 개수 줄어든다.
        car = fe;//필드의 다형성
        
        //car.water(); 예외 발생, car의 근본이 Car이기 때문
        
        fe2 = (FireEngine)car; //다운캐스팅 . 형변환 생략 불가능. 다룰 수 있는 멤버 개수 늘어남
        fe2.water();
 
    }
 
}
 
cs

car은 Car(조상)의 인스턴스이고 fe는 FireEngine(자손)의 인스턴스인데

자손의 객체를 조상에 대입하고 있습니다.

다형성때문에 가능합니다.

 

이 부분을 보시면 Car클래스에는 water가 없기떄문에 사용할 수 없습니다.

자손은 조상의 멤버를 모두 사용할 수 있지만, 조상은 자손의 멤버를 사용하지 못합니다.

근본이 Car이기에 Car에 있는 멤버만을 사용할 수 있습니다.

 

fe2 에 car을 집어넣고 있는데 형변환을 해서 집어넣고 있습니다.

car은 조상, fe2는 자손이므로 조상타입에서 자손타입으로 형변환 하는 것 즉, 다운 캐스팅이므로 형변환 코드를 생량할 수 없습니다.

fe2는 근본이 FireEngine이기에 water메서드를 사용할 수 있습니다.

 

<실행결과>

 

 

<실행클래스2>

 

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
28
29
30
31
32
33
package sec01_exam;
 
public class CastingEx2 {
 
    public static void main(String[] args) {
 
 
        Car car = new Ambulance();
        FireEngine fe = new FireEngine();
        Ambulance al = new Ambulance();
        Car car2 = null;
        
     
        fe.drive();
        fe.water();
        //형변환은 상속관계에서만 성립한다.
        //fe= (FireEngine)al;
        
        //car = fe;
        //컴파일은 ok, 실행시 에러가 발생 (ClassCastException발생)
        //fe= (FireEngine)car;
        al = (Ambulance)car;
        al.siren();
        fe.water();
        
        car2 = fe;
        car2.drive();
        
 
    }
 
}
 
cs

 

다형성의 개념으로 조상으로 자손의 인스턴스를 생성할 수 있습니다.

 

상속 관계가 아니기에 형변환은 불가능합니다.

 

상속관계이므로 형변환이 가능하며, 다운캐스팅을 하고 있습니다.

 

<출력결과>

 


3. instanceof 연산자

실제 형변환이 가능한지를 알아볼때 쓰는 것이 유용하다.

 

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
28
29
30
31
32
33
34
package sec02_exam;
 
class Car{}
class FireEngine extends Car{}
class Ambulance extends Car{}
 
public class InstanceOfEx1 {
 
    public static void main(String[] args) {
        
        FireEngine fe = new FireEngine();
        FireEngine fe2 = null;
        
        Object obj = fe;//업캐스팅
        Car car = fe; //업캐스팅
        
        //instanceof 연산자의 결과가 참이면 형변환이 가능하다
        if (fe instanceof FireEngine) {
            System.out.println("This is a FireEngine instance");
        }
        if (fe instanceof Car) {
            System.out.println("This is a Car instance");
        }
        if (fe instanceof Object) {
            System.out.println("This is a Object instance");
        }
        //아래 예외가 발생하는 이유는?FireEngine과 Ambulance는 아무런 관계가 없다
//        if (fe instanceof Ambulance) {
//            System.out.println("This is a Ambulance instance");
//        }
    }
 
}
 
cs

fe instanceof FireEngine 

은 fe가 FireEngine의 객체냐? 라고 묻는 것입니다.

 

fe instanceof Car

은 fe가 Car의 인스턴스냐? 라고 묻는 것입니다.

Car이 조상이므로 true입니다.

 

fe instanceof Object 

는 fe가 Object의 인스턴스냐? 라고 묻는 것입니다.

Object가 조상이므로 true입니다.

 

<출력결과>

 

 

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
28
29
30
31
32
33
34
35
36
37
38
package sec02_exam;
 
//하나의 java파일에는 public이라는 제어자는 반드시 하나만 있어야 합니다.
//조상클래스
class Parent
{}
//자손클래스
class Child extends Parent
{}
 
public class InstanceOfEx2 {
   
   public static void main(String[] args) {
      //parentA 참조변수는 필드의 다형성이 적용된 코드.
      Parent parentA = new Child();
      
      method(parentA);
      method(new Child());
      
      
      Parent parentB = new Parent();
      method(parentB);
      method(new Child());
      }
 
   public static void method(Parent parent) {//Parent 와 자손타입 다 들어올 수 있음
      if(parent instanceof Child) { //왼-> 오 업캐스팅되면 true, 다운 캐스팅 되면 false
          //우측에 조상이 와야함
         //서로 상속 관계에 있어서 instanceof연산자의 결과가 true이므로 
         //강제캐스팅이 가능.
         Child child = (Child)parent;
         System.out.println("Child로 변환 성공");
      }
      else {
         System.out.println("Child로 변환 실패");
      }      
   }
}
cs

이 부분을 보시면 method의 매개변수로 Parent를 받고 있습니다.

그러면 매개변수로는 Parent나 Parent의 자손클래스의 객체가 올 수 있습니다.

 

매개변수로 받은 객체가 instanceof Child냐고 묻습니다.

맞다면 child객체를 생성해서 Child로 형변환을 해줍니다.

 

여기서 보시면 parentA는 Child로 객체 생성했으니 true

두번째는 new Child를 넘겼으니 당연히 true

세번째는 parentB가 Parent의 객체이므로 false입니다.

 

<출력결과>


 

728x90