article thumbnail image
Published 2022. 9. 29. 15:21
상속/다형성

왜 상속과 다형성이라는 개념을 쓸까?

근본적인 이유부터 생각해 보자.

 

예를 들어 생각해 보자.

과일 밑에 포도,사과,딸기   가 있다고 해보자

 

과일에 해당되는 것의 정보를 바꾸고 싶을때

상속을 시켜 놓지 않았다면 일일히 다 바꿔야 한다. 하지만 과일이라는 부모클래스로부터 자식클래스로 상속을 시켜 놓으면

부모 클래스에서만 수정을 하면 공통된 상속시킨 부분을 한번에 수정이 가능하다.

 

코드를 통해 확인해 보자

Shape에서 상속받는 클래스

Circle         Rectangle           Triangle이 있다.

 

printArea(new Circle());
printArea(new Triangle());
printArea(new Rectangle());

 

private static void printArea(Circle c) {
        c.area();
        System.out.println("넓이는 "+c.res);
}

private static void printArea(Rectangle r) {
        r.area();
        System.out.println("넓이는 "+r.res);
}

private static void printArea(Triangle t) {
        t.area();
        System.out.println("넓이는 "+t.res);
}

 

=> 이렇게 3개의 메서드를 만든걸 하나로 합치고 싶다......어떻게 하면될까?
정답은 다형성에 있다.

 

 

업캐스팅을 활용해서 매개변수의 객체를 Shape(부모)로 바꿔주면 3개의 메서드를 합칠 수 있다.

(자식클래스들의 공통된 메서드가 있을때 다형성을 이용해서 바꿀 수 있다.)

 

그렇다면 합친 메서드로 자식 클래스의 필드에 접근하고 싶으면 어떻게 해야 할까?

=> Shape s로 변환된 상태에서는 자식 필드에 접근할 수 없다.......

=> 다시 다운캐스팅 해줘야한다.

s.area(); 를 수행하면

처음에 생성했던 인스턴스의 메서드가 실행된다.

s가 힙 영역에 등록될때 가지고 있던 area 메서드를 실행하곘다는 의미이다.

 

 Shape s는 그냥 자료형일 뿐이다...실제는 new Circle() 또는 new Triangle() 또는 new Rectangle()이다.

 

결론적으로는  area가 Overriding 된거다.

 

 

upcasting/downcasting

 

 

upcasting : sub타입 인스턴스를 super 타입으로 참조하는걸

 

upcasting/downcasting을 할 수 있는 기준은 우변에 new로 생성된 곳을 기준으로 생각하면된다.

 

좌변이 현재 참조되고 있는 현 상태라고 생각하면된다.

 

casting

 

People e = new Employee();
People s = new Student();

Employee클래스에서 eat() 메서드를 Override 를 했기때문에 

e.eat();   사용가능

//  e.company();     (불가능)

=> 좌변이 People로 업캐스팅 했기 때문에 Employee에 있는 메서드를 못쓰는 거다.

// 현재 참조되고 있는 현상태에서 없는 메서드는 쓸 수가 없다.


Employee e2 = (Employee)e;                          //downcasting : 강제 형변환(명시적 형변환)
                                                                         //up casting된 인스턴스를 sub  타입으로 재 형변환

s.eat();
//s.school();  

=>좌변이 People로 업캐스팅 했기 때문에 Student에 있는 메서드를 못쓰는 거다


*중요
People p3 = new People();
Employee e3 = (Employee)p3;
이러한 다운캐스팅은 불가능하다.

왜냐하면 처음에 선언한 p3는 인스턴스가 People클래스 생성되었기 때문이다.

다운캐스팅이 가능하기 위해서는 처음에 생성한 인스턴스가 자식클래스여야 나중에 부모로 업캐스팅하더라도

근본이 되는 인스턴스가 자식이기 때문에 다운캐스팅이 가능한 것이다.

 

upcasting/downcasting 예시

 

Bird b = new Bird();
System.out.println(b);

 

원래 Bird(자식클래스)에 toString메서드가 없으면 animal(부모)의 toString 메서드가 출력된다.  
(동물입니다.)
만약에 animal(부모)도 없다면 최상위 클래스 객체인 object 객체의 toString메서드가 출력되서
참조형 변수 주소값이 찍힌다.

Animal a = new Bird();  //업캐스팅 된거다.(원래 Bird 타입인데 Animal타입으로)

Bird c = (Bird) a;           //다운캐스팅 가능하다

                                     =>원래 근본이 되는 a의 클래스가 Bird기 때문이다.

 


우변에 생성된 인스턴스(= 근본이 되는 인스턴스)를 기준으로 업캐스팅 다운캐스팅 가능한지 생각해보면될것같다.

 


원래 인스턴스를 기준으로 업캐스팅은 그냥 가능하지만
다운캐스팅을 하려면 원래 인스턴스가 근본이 되는 클래스로 돌아가려고 하지 않는 이상 불가능하다.

new Bird로 생성된 객체 Bird는

Bird 가 Animal로 가는건 가능  ,   Bird 가 Eagle로 가는건 불가능

Bird bb = new Eagle();

Animal aa = new Eagle();

Animal aa2 = bb;

Bird bb2 = (Bird) aa2;

Eagle ee = (Eagle)bb2;

 

*중요

다운캐스팅은 항상 확인하고 해줘야 한다.

 

if(ee instanceof BladEagle) {
        BladEagle be = (BladEagle)ee;
}else {
        System.out.println("다운 캐스팅 불가");
}

 


Bird bbb = new Bird();
Animal aaa = bbb;

if(aaa instanceof Cat) {
        Cat ccc = (Cat)aaa;
}else {
        System.out.println("다운 캐스팅 불가");
}

 

 

 

다중상속이 불가능한 이유

 

자바에서는 플랫폼 독립성을 지키기 위해 다중상속 기능을 포기했다.

 

타이거                   라이언

-발톱                     -발톱

-줄무늬                  -갈기

- 꼬리                      -근육

 

라이거

-발톱

-꼬리

-갈기

 

라이거의 발톱은 누구꺼라고 할수 있나?
(다중상속을 할 경우 이런 모호한 경우가 발생한다.)

 

 

 

@Override

 

어노테이션  @Override를 왜 사용하는가?

 

오타를 찾아줄수 있다....!

 

 

자식클래스에서 메서드 오버라이딩 할떄 반드시 같거나 큰범위의 접근 지정자만 써야한다.

 

 

 

 

오늘의 생각

 

스택에서 메서드영역에서의 메서드를 불러오고, 힙영역에서 참고하는 부분을 불러오고? 

(이게 맞는건가?)

 

 

 

 

클래스 사이 형변환이나, 기본 자료형의 형변환도

컴팡이러가 아닌 JVM의 클래스 로더에서 일어난다.

 

생성자 p354 참고

복사했습니다!