[Java] 다형성 (1)

SeongEon Kim·2022년 5월 4일
0

JAVA

목록 보기
30/52
  1. 메소드와 다형성

    다형성이란, 하나의 메소드나 클래스가 있을 때 이것들이 다양한 방법으로 동작하는 것을 의미한다.

    아래 코드 예시를 통해 이해해보자.

    package org.opentutorials.javatutorials.polymorphism;
    class O{
       public void a(int param){
           System.out.println("숫자출력");
           System.out.println(param);
       }
       public void a(String param){
           System.out.println("문자출력");
           System.out.println(param);
       }
    }
    public class PolymorphismOverloadingDemo {
       public static void main(String[] args) {
           O o = new O();
           o.a(1);;
           o.a("one");
       }
    }

 클래스 O의 메소드 a는 두개의 본체를 가지고 있다. 동시에 두개의 본체는 하나의 이름인 a를 공유하고 있다. 같은 이름이지만 서로 다른 동작 방법을 가지고 있기 때문에 오버로딩은 다형성의 한 예라고 할 수 있다.
 
2. 클래스와 다형성

package org.opentutorials.javatutorials.polymorphism;
class A{}
class B extends A{}
public class PolymorphismDemo1 {
public static void main(String[] args) {
A obj = new B();
//B를 obj라는 변수에 담아서 인스턴스화 했다.
}
}

 클래스 B로 객체를 만드는데 그 객체가 담겨있는 데이터 타입이 A다.
 즉, 클래스 B는 A를 상속받고 있다. 클래스 B를 인스턴스화 시키는데, 그 인스턴스화 시킨 인스턴스를 obj라는 변수에 담았다. 그 obj라는 변수는 클래스 A를 데이터 타입을 하고 있다. 더 쉽게 표현하면, 클래스 B로 인스턴스를 만들었지만 그 인스턴스는 클래스 A의 데이터 타입 행세를 하고 있다고 말할 수 있다.
 
 이렇게 하는 이유를 아래 코드를 통해 알아보자.

package org.opentutorials.javatutorials.polymorphism;
class A{
public String x(){return "x";}
//클래스 A는 메소드 x가 정의되고 있고, x라는 문자열을 리턴하고 있다.
}
class B extends A{
public String y(){return "y";}
// 클래스 B는 클래스 A를 상속하며, 메소드 y를 정의하고 있다. y를 리턴하고 있다.
}
public class PolymorphismDemo1 {
public static void main(String[] args) {
A obj = new B();
obj.x();
obj.y();
// 여기서 오류 발생
}
}

 코드 밑부분 보면 클래스 A 행세를 하고 있는 obj가 메소드 x와 y를 호출하고 있다. 그러나 이 코드는 오류가 뜬다. 
 왜냐하면 클래스 B를 인스턴스화한 obj라는 변수가 A행세를 하고 있다. 그리고 바로 밑에서 obj.x()라고 x를 호출하고 있는데, 클래스 B안에 메소드 x는 존재하지 않더라도 A행세를 하고 있으므로 실행이 되지만, 그 밑의 obj.y()는 클래스 A에서 정의되지 않았으므로 실행되지 않는다.
 
 즉 클래스 B의 데이터 형을 클래스 A로 하면 클래스 B는 마치 클래스 A인것처럼 동작하게 되는 것이다. 클래스 B를 사용하는 입장에서는 클래스 B를 클래스 A인것처럼 사용하면 된다.
 
 위의 코드를 아래와 같이 수정해보자.
 

package org.opentutorials.javatutorials.polymorphism;
class A{
public String x(){return "A.x";}
}
class B extends A{
public String x(){return "B.x";}
public String y(){return "y";}
}
public class PolymorphismDemo1 {
public static void main(String[] args) {
A obj = new B();
System.out.println(obj.x());
}
}

 
  위 코드를 실행시켰을 때 출력되는 결과물은 B.x 이다.
 진짜 헷갈린다..왜지???
  A행세를 하는데 왜 B에 있는 메소드에 따라 출력하는 것일까.
 
 생활코딩은 아래와 같이 따져 보고 있다.
 
 
  1) 클래스 B의 데이터 타입을 클래스 A로 인스턴스화 했을 때 클래스 B의 메소드 y는 마치 존재하지 않는 것처럼 실행되지 않았다. => 클래스 B가 클래스 A화 되었다.
  2) 클래스 B의 데이터 타입을 클래스 A로해서 인스턴스화 했을 때 클래스 B의 메소드 x를 실행하면 클래스 A에서 정의된 메소드가 아니라 클래스 B에서 정의된 메소드가 실행 되었다. => 클래스 B의 기본적인 성질은 그대로 간직하고 있다.
  
 간략히 정리하면 이렇다.
 
 클래스 B를 클래스 A의 데이터 타입으로 인스턴스화 했을 때 클래스 A에 존재하는 맴버만이 클래스 B의 맴버가 된다. 동시에 클래스 B에서 오버라이딩한 맴버의 동작방식은 그대로 유지한다.
 
 아래 코드를 좀 더 봐볼까?
 

package org.opentutorials.javatutorials.polymorphism;
class A{
public String x(){return "A.x";}
}
class B extends A{
public String x(){return "B.x";}
public String y(){return "y";}
}
class B2 extends A{
public String x(){return "B2.x";}
}
public class PolymorphismDemo1 {
public static void main(String[] args) {
A obj = new B();
A obj2 = new B2();
System.out.println(obj.x());
// 출력물 : B.x
System.out.println(obj2.x());
// 출력물 : B2.x
}
}


 obj에 담겨있는 실제 인스턴스는 B, obj2에 담겨있는 실제 인스턴스는 B2이다.
 하지만 두개의 클래스 모두 A행세를 하고 있다. 따라서 클래스 A에서 정의한 메소드 x만 호출을 할 수 있게 된다. 부모클래스에서 정의한 메소드만 호출할 수 있는 것이다. 부모행세를 하고 있으므로 자식클래스에서 추가한 메소드는 존재하지 않게 된다. 그러나, 자식클래스에서 부모 클래스에 있는 메소드를 오버라이딩했다면 실제 동작은 자식클래스에서 오버라이딩한 내용이 호출된다. 반면에, 부모클래스에서 정의하지 않는 메소드 y를 클래스 B를 인스턴스한 메소드가 호출하려고 하면 y메소드는 부모클래스에서 정의된 바 없으므로 존재하지 않는 메소드가 된다.
 
 이것이 상속과 오버라이딩 그리고 형변환을 이용한 다형성이다.
profile
꿈을 이루는 사람

0개의 댓글