-
다형성, instanceof, 메서드 오버라이딩JAVA/개념 - 김영한 강의 2024. 10. 8. 08:02
다형성
- 하나의 객체가 다른 타입으로 사용될 수 있다는 뜻이다.
- 부모는 자식을 품을 수 있다. 직계 뿐만이 아니라 손자 등 모든 자식 타입을 참조할 수 있다. 이렇게 다양한 형태를 참조할 수 있다고 해서 다형적 참조라 한다.
- Parent poly = new Parent()
Parent poly = new Child()
Parent poly = new Grandson()
- Parent poly = new Parent()
캐스팅
- 업캐스팅(upcasting): 자식 -> 부모 타입으로 변경
- 다운캐스팅(downcasting): 부모 -> 자식 타입으로 변경
다운캐스팅
public class Parent { public void parentMethod() { System.out.println("Parent.parentMethod"); } }
public class Child extends Parent { public void childMethod() { System.out.println("Child.childMethod"); } }
public class PolyMain { public static void main(String[] args) { // 부모 변수가 부모 인스턴스 참조 System.out.println("Parent -> Parent"); Parent parent = new Parent(); parent.parentMetho(); // 자식 변수가 자식 인스턴스 참조 System.out.println("Child -> Child"); child child = new Child(); child.parentMethod(); child.childMethod(); // 부모 변수가 자식 인스턴스 참조(다형적 참조) System.out.println("Parent -> Child"); Parent poly = new Child(); poly.parentMehod(); //Child child1 = new Parent(); 자식은 부모를 담을 수 없다. //자식의 기능은 호출할 수 없다. 컴파일 오류 발생 //poly.childMethod(); } }
Parent poly = new Child()
- 부모 타입의 변수가 자식 인스턴스를 참조한다. 즉, 부모는 자식을 담을 수 있다.
- 참고로 반대는 불가능하다. Child child1 = new Parent(); // 컴파일 오류 발생
- Child 인스턴스를 생성했기 때문에 메모리 상에 Child와 Parent 모두 생성된다.
- poly.parentMehod(); // 생성된 참조값을 Parent 타입의 변수인 poly 에 담아둔다는 뜻이다
- poly.childMethod(); // 자식의 기능은 호출 할 수 없다!!
Child child = (Child) poly // Parent poly 타입을 Child로 만듦(다운캐스팅)
- (타입)처럼 괄호에 그 사이에 타입을 지정하면 참조 대상을 특정 타입으로 변경할 수 있다 = 캐스팅
- 다운캐스팅을 통해 따라서 Parent poly가 일시적으로 Child 타입이 됐다
- 캐스팅을 한다고해서 Parent poly 타입이 변하는 것은 아니다. 참조값이 Child 타입이 되는것이다
- child.childMethod()를 호출할 수 있게 되었다.
일시적 다운 캐스팅 - 해당 메서드를 호출하는 순간만 다운캐스팅public class CastiongMain2 { public static void main(String[] args) { // 부모 변수가 자식 인스턴스 참조(다형적 참조) Parent poly = new Child(); ((Child) poly).childMethod(); } }
이 또한 poly가 Child 타입으로 바뀌는 것이 아니다. 참조값이 Child 타입이 되는 것이다.
업 캐스팅
//upcasting vs downcasting public class CastingMain3 { public static void main(String[] args) { Child child = new Child(); Parent parent1 = (Parent) child; //업캐스팅은 (타입) 생략 가능, 생략 권장 Parent parent2 = child; //업캐스팅 생략. parent1.parentMethod(); parent2.parentMethod(); } }
- 부모 타입으로 변환하는 경우 (타입)을 생략할 수 있다.
A a = new B() : A로 업케스팅
B b = new B() : 자신과 같은 타입
C c = new B() : 하위 타입은 대입할 수 없음, 컴파일 오류
C c = (C) new B() : 하위 타입으로 강제 다운캐스팅, 하지만 B 인스턴스에 C와 관련된 부분이 없으므로 잘
못된 캐스팅, ClassCastException 런타임 오류 발생instanceof
다양한 대상을 참조하는 다형성이 어떤 인스턴스를 참조하고 있는지 확인하려면 어떻게 해야할까?
if (객체 instanceof 클래스명) { // 객체가 클래스명 타입인 경우 실행될 코드 }
ex) Parent는 자신의 인스턴스 혹은 자식의 인스턴스를 참조할 수도 있다. 이를 확인하려면?
public class CastingMain5 { public static void main(String[] args) { Parent parent1 = new Parent(); System.out.println("parent1 호출"); call(parent1); Parent parent2 = new Child(); System.out.println("parent2 호출"); call(parent2); } private static void call(Parent parent) { parent.parentMethod(); if(parent instanceof Child) { // Child 클래스의 parent 인스턴스인가? 즉 parent가 Child를 참조하나? System.out.println("Child 인스턴스 맞음"); Child child = (Child) parent; child.childMethod(); } } }
실행결과
parent1 호출
Parent.parentMethod
parent2 호출
Parent.parentMethod
Child 인스턴스 맞음 // parent가 Child클래스의 인스턴스일 경우에만 뜨니까!!
Child.childMethodnew Parent() instanceof Parent Parent p = new Parent() //같은 타입 true new Child() instanceof Parent Parent p = new Child() //부모는 자식을 담을 수 있다. true new Parent() instanceof Child Child c = new Parent() //자식은 부모를 담을 수 없다. false new Child() instanceof Child Child c = new Child() //같은 타입 true
메서드 오버라이딩
- 오버라이딩: 부모 타입에서 정의한 기능을 자식 타입에서 재정의하는 것
다형성에서 메서드 오버라이딩의 핵심은,
더 하위 자식의 오버라이딩 된 메서드가 항상 우선권을 가진다는 점이다.
public class Parent { public String value = "parent"; public void method() { System.out.println("Parent.method"); } }
public class Child extends Parent { public String value = "child"; @Override public void method() { System.out.println("Child.method"); } }
public class OverridingMain { 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); //변수는 오버라이딩X poly.method(); //메서드 오버라이딩! } }
Parent poly = new Child();
- poly 변수는 Parent 타입이다. 따라서 poly.value , poly.method() 를 호출하면 인스턴스의 Parent 타입에서 기능을 찾아서 실행한다.
- poly.value : Parent 타입에 있는 value 값을 읽는다.
- poly.method() : Parent 타입에 있는 method() 를 실행하려고 한다. 그런데 하위 타입인 Child.method() 가 오버라이딩 되어 있다. 오버라이딩 된 메서드는 항상 우선권을 가진다. 따라서 Parent.method() 가 아니라 Child.method() 가 실행된다.
'JAVA > 개념 - 김영한 강의' 카테고리의 다른 글
인터페이스 (0) 2024.10.21 추상 클래스 (0) 2024.10.15 상속(Inheritance), @Override, super (0) 2024.09.27 클래스 메서드, 인스턴스 메서드 (1) 2024.09.17 멤버변수의 종류와 자바의 메모리 구조(메서드, 스택, 힙) (1) 2024.09.15