다형성
사용 방법은 동일하지만 다양한 객체를 이용해서 다양한 실행결과가 나오도록 하는 성질이며, 다형성을 구현하려면 메소드 재정의와 타입 변환이 필요하다.
자동 타입 변환(promotion)
자식은 부모 타입으로 자동 타입 변환이 가능하며, 자동 타입 변환은 프로그램 실행 도중에 자동적으로 타입 변환이 일어나는 것을 말함.
자동 타입 변환의 개념은 자식은 부모의 특징과 기능을 상속받기 때문에 부모와 동일하게 취급될 수 있다는 것.
바로 위의 부모가 아니더라도 상속 계층에서 상위 타입이라면 자동 타입 변환이 일어날 수 있음.
// 자동 타입 변환
package sec02.exam01;
class A {}
class B extends A{}
class C extends A{}
class D extends B{}
class E extends C{}
public class PromotionExample {
public static void main(String[] args) {
B b = new B();
C c = new C();
D d = new D();
E e = new E();
A a1 = b;
A a2 = c;
A a3 = d;
A a4 = e;
B b1 = d;
C c1 = e;
// B b3 = e; // 상속 관계에 있지 않기 때문에 컴파일 에러
// C c2 = d; // 상속 관계에 있지 않기 때문에 컴파일 에러
}
}
* 부모 타입으로 자동 타입 변환된 이후에는 부모 클래스에 선언된 필드와 메소드만 접근이 가능하며, 비록 변수는 자식 객체를 참조하지만 변수로 접근 가능한 멤버는 부모 클래스 멤버로만 한정되지만, 예외가 있는데 메소드가 자식 클래스에서 재정의 되었다면 자식 클래스의 메소드가 대신 호출됨.
// 자동 타입 변환 후의 멤버 접근
package sec02.exam02;
public class Parent {
public void method1() {
System.out.println("Parent-method1()");
}
public void method2() {
System.out.println("Parent-method2()");
}
}
// 자동 타입 변환 후의 멤버 접근
package sec02.exam02;
public class Child extends Parent {
@Override // 재정의
public void method2() {
System.out.println("Child-method2()");
}
public void method3() {
System.out.println("Child-method3()");
}
}
// 자동 타입 변환 후의 멤버 접근
package sec02.exam02;
public class ChildExample {
public static void main(String[] args) {
Child child = new Child();
Parent parent = child; // 자동 타입 변환
parent.method1();
parent.method2(); // 재정의된 메소드가 호출됨
//parent.method3(); // 호출 불가능
}
}
필드의 다형성
필드의 타입을 부모 타입으로 선언하면 다양한 자식 객체들이 저장될 수 있기 때문에 필드 사용 결과가 달라질 수 있음.
부모 클래스를 상속하는 자식 클래스는 부모가 가지고 있는 필드와 메소드를 가지고 있어 사용 방법이 동일한데, 자식 클래스는 부모의 메소드를 재정의해서 메소드의 실행 내용을 변경함으로써 더 나은 실행 결과가 나오게 할 수 있으며 자식 타입을 부모 타입으로 변환할 수 있음.
매개 변수의 다형성
자동 타입 변환은 필드의 값을 대입할 때에도 발생하지만, 주로 메소드를 호출할 때 많이 발생하는데 메소드를 호출할 때에는 매개 변수의 타입과 동일한 매개값을 지정하는 것이 정석이지만, 매개값을 다양화하기 위해 매개 변수에 자식 객체를 지정할 수도 있음.
매개 변수의 타입이 클래스일 경우, 해당 클래스의 객체뿐만 아니라 자식 객체까지도 매개값으로 사용할 수 있는데, 즉 매개값으로 어떤 자식 객체가 제공되느냐에 따라 메소드의 실행 결과는 다양해 질 수 있다. 자식 객체가 부모의 메소드를 재정의했다면 메소드 내부에서 재정의된 메소드를 호출함으로써 메소드의 실행결과는 다양해 짐.
강제 타입 변환(casting)
부모 타입을 자식 타입으로 변환하는 것으로, 자식 타입이 부모 타입으로 자동 타입 변환한 후 다시 자식 타입으로 변환할 때 강제 타입 변환을 사용할 수 있음.
// 부모 클래스
package sec02.exam03;
public class Parent {
public String field1;
public void method1() {
System.out.println("Parent-method1()");
}
public void method2() {
System.out.println("Parent-method2()");
}
}
// 자식 타입
package sec02.exam03;
public class Child extends Parent {
public String field2;
public void method3() {
System.out.println("Child-method3()");
}
}
// 강제 타입 변환
package sec02.exam03;
public class ChildExample {
public static void main(String[] args) {
Parent parent = new Child(); // 자동 타입 변환
parent.field1 = "data1";
parent.method1();
parent.method2();
Child child = (Child) parent; // 강제 타입 변환
child.field2 = "yyy";
child.method3();
}
}
// 실행결과
// Parent-method1()
// Parent-method2()
// Child-method3();
객체 타입 확인
강제 타입 변환은 자식 타입이 부모 타입으로 변환되어 있는 상태에서만 가능하기 때문에 처음부터 부모 타입으로 생성된 객체는 자식 타입으로 변환할 수 없는데, 이때 어떤 객체가 어떤 클래스의 인스턴스인지 확인하기 위해 instanceof 연산자를 사용.
이 연산자는 주로 매개값의 타입을 조사할 때 사용되며, 메소드 내에서 강제 타입 변환이 필요한 경우 반드시 매개값이 어떤 객체인지 instanceof 연산자로 확인하고 안전하게 강제 타입 변환을 해야 함.
boolean result = 좌향(객체) instanceof 우향(타입)
instanceof 연산자의 좌항에는 객체가 오고 우항에는 타입이 오는데, 좌항의 객체가 우항의 인스턴스이면, 즉 우향의 타입으로 객체가 생성되었다면 true를 리턴하고 그렇지 않으면 false를 리턴함.
🔘 클래스 타입 변환: 다른 클래스 타입으로 객체를 대입하는 것
🔘 자동 타입 변환: 자식 객체를 부모 타입 변수에 대입할 때에는 자동으로 타입이 변환됨.
🔘 강제 타입 변환: 자식 객체가 부모 타입으로 변환된 상태에서 다시 원래의 자식 타입으로 변환하고자 할 때 캐스팅( ) 연산자를 사용해서 강제 타입 변환할 수 있다.
🔘 Instanceof 연산자: 객체가 어떤 타입인지 조사할 때 instanceof 연산자를 사용하며, 주로 강제 타입 변환 전에 변환이 가능한지 조사할 때 사용함.
🔘 다형성: 객체 사용 방법은 동일하지만 실행결과가 다양하게 나오는 성질을 말하며, 다형성을 구현하는 기술은 메소드 재정의와 타입 변환. 자식 객체가 재정의된 메소드를 가지고 있을 경우, 부모 타입으로 자동 타입 변환 후에 메소드를 호출하면 재정의된 자식 메소드가 호출 되면서 다양한 실행 결과를 가져올 수 있음.
'Java' 카테고리의 다른 글
| [Java] 인터페이스 (0) | 2025.11.14 |
|---|---|
| [Java] 추상 클래스 (0) | 2025.11.14 |
| [Java] 상속 (0) | 2025.11.10 |
| [Java] 패키지와 접근 제한자 (0) | 2025.11.10 |
| [Java] 인스턴스 멤버와 정적 멤버 (0) | 2025.11.10 |