네트워크 캠퍼스/JAVA
240111 매개 변수의 다형성, 강제 타입 변환
gayeon_
2024. 1. 12. 10:04
매개 변수의 다형성
- promotion(자동형변환)은 멤버 변수의 값을 대입할 때도 발생하지만, 메서드를 호출할 때 사용하는 매개 변수에도 발생할 수 있다.
- 보통 메서드를 호출할 때는 메서드 선언부에서 지정한 데이터 타입과 일치하는 매개값을 전달하여 호출하지만, 매개 변수에 다형성을 적용하면 자식 객체를 전달할 수도 있다.
강제 타입 변환(Type Casting)
- 강제 타입 변환은 부모 타입을 자식 타입으로 변환하는 것을 말한다.
- 객체에서 타입 캐스팅을 사용하려면 우선 먼저 Promotion이 일어나야 한다. 즉, 부모 타입으로 한번 형 변환이 된 자식 객체만 강제 타입 변환을 사용할 수 있다.
- Promotion이 일어나면 자식 클래스가 가지고 있는 재정의되지 않은 메서드를 사용할 수 없다는 단점이 있다. 이 단점을 극복하기 위해 강제 타입 변환을 사용하여 자식 메서드를 호출하는 방법을 사용한다.
Promotion 예제
// 부모 클래스
package casting;
public class Parent {
public void method1() {
System.out.println("부모측 1번 메서드 호출!");
}
public void method2() {
System.out.println("부모측 2번 메서드 호출!");
}
}
// 자식 클래스 1
package casting;
public class Child extends Parent{
@Override
public void method2() {
System.out.println("자식쪽에서 재정의한 2번 메서드!");
}
public void method3() {
System.out.println("자식만 갖고 있는 3번 메서드!");
}
}
// 자식 클래스2
package casting;
public class Child2 extends Parent {
@Override
public void method2() {
System.out.println("2번 자식의 2번 메서드!");
}
public void method3() {
System.out.println("2번 자식의 3번 메서드!");
}
}
// 메인 클래스
package casting;
public class MainClass1 {
public static void main(String[] args) {
// Promotion이 적용되면 자식 클래스에만 정의된 요소 조회 불가능
Parent p = new Child();
p.method1(); // Parent에만 정의된 메서드
p.method2(); // 오버라이딩된 메서드는 타입 상관없이 인스턴스 내 자식쪽 호출
// p.method3(); // p타입 변수로는 자식쪽에만 정의된 요소는 호출 불가능
System.out.println("-----------------------");
}
}
Parent p = new Child();를 실행했을 때의 메모리 구조
new Child();로 만들었기 때문에 인스턴스는 Child로 생성된다.
그 후 부모쪽으로 promotion이 되기 때문에 p가 사용 가능한 영역은 Parent 뿐이다.
하지만 method2()의 경우에는 오버라이드됐기 때문에 부모쪽 원본 메서드가 아닌 자식쪽에서 재정의한 메서드로 사용된다.
메인 메서드 수정
// 메인 메서드 수정
package casting;
public class MainClass1 {
public static void main(String[] args) {
// Promotion이 적용되면 자식 클래스에만 정의된 요소 조회 불가능
Parent p = new Child();
p.method1(); // Parent에만 정의된 메서드
p.method2(); // 오버라이딩된 메서드는 타입 상관없이 인스턴스 내 자식쪽 호출
// p.method3(); // p타입 변수로는 자식쪽에만 정의된 요소는 호출 불가능
System.out.println("-----------------------");
Child c = (Child)p; // 부모타입 변수를 자식타입으로 강제형변환
c.method2(); // 위와 동일하게 자식측 method2() 호출
c.method3(); // 형 변환 후에는 자식쪽에만 있는 요소도 호출 가능
Child cc = new Child(); // 애초에 자식타입으로 인스턴스 대입시에도
cc.method3(); // 자식쪽에만 있는 요소 호출 가능
}
}
(Child)로 강제형변환을 하지 않으면 부모타입인 p를 자식타입인 c에 대입할 수 없다.
c는 부모타입 변수인 p를 자식타입으로 강제형변환을 했기 때문에 Parent, Child 모두 사용할 수 있다.
// 메인 메서드2
package casting;
public class MainClass2 {
public static void main(String[] args) {
// Parent 타입에는 Child, Child2 모두 대입 가능
Parent p1 = new Child();
p1.method2();
// p1.method3();
// Parent 타입으로는
// Child1의 method2도, Child2의 method2도 호출 가능
// method2는 Parent에도 정의되어있지만 Child와 Child2에도 정의된
// 오버라이딩된 메서드이기 때문에 호출 가능하다.
}
}
자식 객체를 Parent 타입으로 Promotion하면 Child1의 method2, Child2의 method2 모두 호출할 수 있다.
new Child();에서 new Child2();로 한군데만 수정하면 Child2의 method2를 호출할 수 있으므로 코드의 유지, 보수를 쉽게 한다.
instanceof
- 자바의 키워드 중에서 instanceof 는 객체가 지정한 클래스의 인스턴스인지 아닌지 검사할 때 사용하는 연산자이다.
- instanceof 연산자의 왼쪽 항의 객체가 오른쪽 항 클래스의 인스턴스 즉, 오른쪽 항의 객체가 생성되었다면 true를 리턴하고, 그렇지 않으면 false를 리턴한다.
ex)
Person p = new Student();
p instanceof Student -> true
instanceof 예제
// 부모 클래스인 Human 클래스
package instanceof_;
public class Human {
private String name;
private int age;
// 생성자 정의
public Human(String name, int age) {
this.name = name;
this.age = age;
}
// void 파라미터로 생성자 호출 시
public Human() {
// this.name = "noname";
// this.age = 0;
this("noname", 0);
}
public void showInfo() {
System.out.println("이름: " + this.name);
System.out.println("나이: " + this.age);
System.out.println("-----------------");
}
}
// 자식 클래스인 Student 클래스
package instanceof_;
public class Student extends Human {
// String, int를 대입하는 생성자
public Student(String name, int age) {
super(name, age);
}
}
// 상속 관계가 없는 Cat 클래스
package instanceof_;
public class Cat {
private String name;
private int age;
public Cat(String name, int age) {
this.name = name;
this.age = age;
}
public void meow() {
System.out.println("야옹 야옹");
}
}
// 메인 클래스
package instanceof_;
public class MainClass {
public static void main(String[] args) {
// Human, Student, Cat 인스턴스 생성
Human h1 = new Human("자바", 20);
h1.showInfo();
Student s1 = new Student("학생", 15);
s1.showInfo();
Cat c1 = new Cat("춘식이", 5);
c1.meow();
System.out.println(h1 instanceof Human); // h1이 Human 객체(인스턴스)인가
System.out.println(s1 instanceof Human); // s1이 Human 객체(인스턴스)인가
}
}
s1은 Human의 자식 클래스에서 생성된 객체이기 때문에 instanceof 연산자를 사용하면 true가 나온다.
하지만 h1 instanceof Student로 하면 false가 나온다.