다형성은 상속관계있는 부모와 자녀와 인스턴스 관계를 생각해보자.
Parent parent = new Parent();
이는 Parent 클래스에 대한 parent 이름의 참조값을 생성하고 Parent 라는 인스턴스를 생성하는 것이다.
부모 타임의 인스턴스만 참고하기 때문에 자식에 대한 정보는 저장되지 않는다.
만약 extend parent 가 된 자식(Child)을 호출한다면,
Child child = new Child();
Child 클래스에 대한 child 의 참조값과 Child의 인스턴스를 생성할 것이다.
Parent poly = new Child()`
이렇게 호출하게 된다면 어떻게 될 것인가?
부모는 자식을 담을 수 있다.
부모 타입은 자식 타입을 담을 수 있다.
`Parent poly` 는 부모 타입이다. `new Child()` 를 통해 생성된 결과는 `Child` 타입이다. 자바에서 부모 타 입은 자식 타입을 담을 수 있다!
Parent poly = new Child()` : 성공
반대로 자식 타입은 부모 타입을 담을 수 없다. 부모 클래스에는 자식에 관한 어떠한 정보가 없기 때문이다.
Child child1 = new Parent()` : 컴파일 오류 발생

그렇다면 부모에서 자식 메서드를 호출할려면 어떻게 해야할 것인가?
이를 위해서 캐스팅이 필요하다.
`Parent poly = new Child()` 와 같이 부모 타입의 변수를 사용하게 되면 `poly.childMethod()` 와 같이 자식 타입의 메서드를 호출할 . 수 없다.
이를 위해서 "다운 캐스팅" 이 필요하다.

자식 타입이 부모타입을 수용할 수 없는데, 강제로 호출하게 하는 방법이 있다
Child child = (Child) poly
호출하는 poly 는 Parent 의 poly 인데 이를 Child child 의 참조값과 동일한 값을 대입하면 된다.
이는 다운캐스팅을 사용하여 부모 타입을 잠깐 자식타입으로 변경하는 것이다.
(Child) 이는 참조타입을 잠시 특정 타입으로 변경할 수 있다.
**실행 순서**
Child child = (Child) poly //다운캐스팅을 통해 부모타입을 자식 타입으로 변환한 다음에 대입 시도
Child child = (Child) x001 //참조값을 읽은 다음 자식 타입으로 지정
Child child = x001 //최종 결과 ```
이는 캐스팅을 한다고 해서 parent poly 의 타입이 변경되는 것이 아닌 참조값만 변경되는 것이다.
캐스팅 용어
업캐스팅: 부모 타입으로 변경
다운캐스팅: 자식 타입으로 변경
캐스팅의 종류
일시적 다운 캐스팅:
다운캐스팅 결과 변수를 담아두는 과정이 번거롭다. 이러한 과정 없이 인스턴스에 있는 하위 클래스의 기능을 바로 호출할 수 있다.
하지만 다운캐스팅을 자동으로 하지 않는 이유는 엄청난 런타임을 발생할 수 있기 때문이다.
Parent parent2 = new Parent() ```
먼저 `new Parent()` 로 부모 타입으로 객체를 생성한다. 따라서 메모리 상에 자식 타입은 전혀 존재하지 않는다. 생성 결과를 `parent2` 에 담아둔다. 이 경우 같은 타입이므로 여기서는 문제가 발생하지 않는다.
Child child2 = (Child) parent2
다음으로 `parent2` 를 `Child` 타입으로 다운캐스팅한다. 그런데 parent2는 `Parent` 로 생성이 되었다. 따라서 메모리 상에
Child자체가 존재하지 않는다. Child 자체를 사용할 수 없는 것이다.
업캐스팅을 할 때 안전한 이유는, 객체를 생성하게 되면 해당 타입의 상위 부모 타입은 무조건 함께 생성하게 된다.
따라서 업캐스팅할 때는 인스턴스가 모두 존재하기 때문에 안전하다.
컴파일 vs 런타임 오류들
컴파일은 변수명 오타, 잘못된 클래스 등등 자바 클래스 실행하기 전에 발생하는 오류
런타임은 프로그램이 실행되면서 발생하는 오류이다.
이는 고객이 프로그램에서 실행하면서 발생할 수 있는 오류이다.
Instanceof
참조하는 대상이 다양한 경우에, 어떤 인스턴스를 참조하고 있는지 확인할려면 어떻게 해야할까?
Parent parent1 = new Parent()
Parent parent2 = new Child()
여기서 `Parent` 는 자신과 같은 `Parent` 의 인스턴스도 참조할 수 있고, 자식 타입인 `Child` 의 인스턴스도 참조할 수 있다.
이때 parent1, parent2 변수가 참조하는 인스턴스의 타입을 확인하고 싶다면 instanceof 키워드를 사용 하면 된다.
다형성과 메서드 오버라이딩
메서드 오버라이딩에서 기억해야 할 점은 **오버라이딩 된 메서드가 항상 우선권을 가진다**는 점이다.
그래서 이름도 기존 기능을 덮어 새로운 기능을 재정의 한다는 뜻의 오버라이딩이다.
package poly.basic.overiding;
public class OverrindingMain {
public static void main(String[] args) {
//자식변수가 자식인스턴스 참조
Child child = new Child();
System.out.println("child --> Child");
System.out.println("value = "+child.value);
child.method();
}
}
package poly.basic.overiding;
public class Parent {
public String value = "Parent";
public void method() {
System.out.println("Parent method");
}
}
package poly.basic.overiding;
public class Child extends Parent{
public String value = "child Value";
@Override
public void method() {
System.out.println("Child Method");
}
}
package poly.basic.overiding;
public class OverrindingMain {
public static void main(String[] args) {
//자식변수가 자식인스턴스 참조
Child child = new Child();
System.out.println("child --> Child");
System.out.println("value = " + child.value);
child.method();
//부모 변수가 부모 인스턴스 참조
Parent parent = new Parent();
System.out.println("parent --> Parent");
System.out.println("value = " + parent.value);
parent.method();
}
}
를 수정한다면, parent 는 같은 참조이기 때문에 자기 자신에서 찾을 것이다.
그렇다면 부모 변수가 자식 인스턴스를 참조할 경우는 어떻게 될 것인가?
package poly.basic.overiding;
public class OverrindingMain {
public static void main(String[] args) {
//자식변수가 자식인스턴스 참조
Child child = new Child();
System.out.println("child --> Child");
System.out.println("value = " + child.value);
child.method();
//부모 변수가 부모 인스턴스 참조
Parent parent = new Parent();
System.out.println("parent --> Parent");
System.out.println("value = " + parent.value);
parent.method();
Parent poly = new Child();
System.out.println("Parent --> Child");
System.out.println("value = " + poly.value);
poly.method();
}
}
child --> Child
value = child Value
Child Method
parent --> Parent
value = Parent
Parent method
Parent --> Child
value = Parent
Child Method
poly변수는 Parent타입이다. 따라서 poly.value, poly.method()를 호출하면 인스턴스의 Parent타입에서 기능을 찾아서 실행한다.
poly.value: Parent타입에 있는 value값을 읽는다.
`poly.method()` : `Parent` 타입에 있는 `method()` 를 실행하려고 한다. 그런데 하위 타입인 `Child.method()` 가 오버라이딩 되어 있다. **오버라이딩 된 메서드는 항상 우선권**을 가진다. 따라서 `Parent.method()` 가 아니라 `Child.method()` 가 실행된다.
'JAVA' 카테고리의 다른 글
[Java] 추상클래스 (0) | 2024.12.06 |
---|---|
[Java] 다형성의 활용 (0) | 2024.12.05 |
[Java] 상속 문제와 풀이 (0) | 2024.11.01 |
[Java] 상속 (1) | 2024.10.30 |
[Java] Static 메서드1 (1) | 2024.10.27 |