ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JAVA] 다형성(Polymorphism)
    Language/Java 2019. 11. 9. 21:18

     

     

    자바에서 다형성이란 같은 이름을 가졌지만 상황에 따라 다른 형태로 해석될 수 있다는 의미입니다.

     

    예를 들어 A 씨는 회사에서는 개발자이고, 집에서는 딸이고, 학원에서는 수강생입니다. 모두 같은 A 씨이지만 각각의 상황에 따라 맡고 있는 역할과 하는 일들이 다릅니다.

     

    이처럼 하나의 객체가 여러 타입을 가질 때, 이를 다형성이라고 합니다.

     

    이러한 다형성은 반드시 상속 관계에서만 성립하는데, 예를 들어 People이라는 클래스를 상속받는 Employee클래스와 Customer클래스가 있습니다.

     

    class People{
    	public void eat(){
        	// 먹기
        }
    	public void breath(){
        	// 숨쉬기
        }
        ...
    }
    
    class Employee extends People{
    	public void work(){
        	// 일
        }
    }
    
    class Customer extends People{
    	public void purchase(){
        	// 구매
        }
    }

     

    그리고 만약 이렇게 생성한 Employee객체들과 Cutomer객체들을 하나의 배열 또는 자료구조에 관리해야 한다면 어떻게 해야 할까요? Employee객체를 담는 배열과 Customer객체를 담는 배열을 따로 만들어야 할까요?

     

    class Main{
    	public static void main(String arg[]){
              People array [] = new People[5];
            	array[0] = new Employee("짱구");
            	array[1] = new Employee("맹구");
            	array[2] = new Customer("철수");
            	array[3] = new Customer("유리");
        }
    }

     

    Employee클래스와 Customer클래스는 모두 People클래스를 상속받아 만들어졌기때문에, 'Employee는 People이다.', 'Customer는 People이다.'와 같은 Is-a관계가 성립합니다. 따라서 위의 코드와 같이 People 타입의 배열을 선언하면 Employee객체와 Customer객체를 모두 담을 수 있는 것입니다.

     

    위와 같은 상황에서 다음과 같은 코드를 실행시켜보면 어떻게 될까요?

     

    public static void main(arg[] str){
          People pemp = new Employee();
          People pcus = new Customer();
          Employee emp = new Employee();
          Customer cus = new Customer();
        
          pemp.eat();			// 가능
          pemp.work();			// 불가능
          pcus.breath();			// 가능
          pcus.purchase();			// 불가능
          emp.eat();			// 가능
          cus.breath();			// 가능
    }

     

    Employee객체를 생성해 People변수에 담은 pemp에서 Employee클래스에 정의된 work() 메소드를 호출하는 경우, Customer객체를 생성해 People변수에 담은 pcus에서 Customer클래스에 정의된 purchase() 메소드를 호출하는 경우 오류가 발생합니다.

     

    자식 클래스에서 부모 클래스의 변수나 메소드에는 접근이 가능하지만, 부모 타입 변수로 선언한 경우 자식 클래스에만 존재하는 변수나 메소드에는 접근할 수 없습니다. 부모 타입 변수로 자식 클래스의 변수나 메소드에 접근하기 위해서는 형 변환이 이루어져야 합니다.

     

    public static void main(arg[] str){
          People pemp = new Employee();
          People pcus = new Customer();
          Employee emp = new Employee();
          Customer cus = new Customer();
        
          Employee pemp2 = (Employee)pemp;
          pemp2.work();			// 가능
          
          Customer pcus2 = (Customer)pcus;
          pcus.purchase();			// 가능
    }

     

    이때 이러한 형변환은 부모 타입 -> 자식 타입으로만 이루어질 수 있습니다. 따라서 형 변환을 하기 전에 형 변환이 가능한지, 부모 자식 관계가 맞는지 확인하는 과정이 필요한데요, 이렇게 확인할 수 있습니다.

     

    public static void main(arg[] str){
          People pemp = new Employee();
          People pcus = new Customer();
          Employee emp = new Employee();
          Customer cus = new Customer();
        
        if(pemp instanceof Employee){
          Employee pemp2 = (Employee)pemp;
          pemp2.work();			// 가능
        }
        if(pcus instanceof Customer){
          Customer pcus2 = (Customer)pcus;
          pcus.purchase();			// 가능
        }
    }

     

    instanceof 연산자(변수 instanceof 타입)를 이용하면 해당 변수를 해당 타입으로 형 변환이 가능한지 알 수 있습니다. true이면 형 변환이 가능하므로 위의 코드에서 처럼 if문으로 조건을 걸어주면 조금 더 확실하게 에러 없이 형 변환을 할 수 있겠습니다.

     

    위에서 부모 타입으로 선언한 경우 자식 클래스에만 존재하는 메소드에 접근할 수 없다고 했습니다. 하지만 부모 클래스에 존재하는 메소드를 자식 클래스에서 오버 라이딩한 경우에는 다릅니다.

     

    class People{
    	public void eat(){
        	// 먹기
        }
    	public void breath(){
        	// 숨쉬기
        }
        ...
    }
    
    class Employee extends People{
    	public void work(){
        	// 일
        }
          public void eat(){
        	system.out.println("emp_eat()호출");	// People클래스의 eat메소드 오버라이딩
            return;
        }
    }
    
    class Customer extends People{
    	public void purchase(){
        	// 구매
        }
          public void eat(){
        	system.out.println("cus_eat()호출");	// People클래스의 eat메소드 오버라이딩
            return;
        }
    }
    public static void main(String[] args) {
              People pemp = new Employee();
              People pcus = new Customer();
              pemp.eat();
              pcus.eat();
    }

     

    다음과 같이 eat()메소드를 오버 라이딩한 후, People이라는 부모 타입으로 변수를 선언한 다음 eat()메소드를 호출하면 People클래스의 eat()메소드가 아닌 각각의 객체에서 오버 라이딩한 eat()메소드의 결과 값이 나타납니다.

     

     

Designed by Tistory.