2017년 7월 6일 목요일

[Java] 추상 클래스(Abstract Class)와 추상 메소드(Abstract Method)

상속(Inheritance)이란 개념에 대해 조금 더 이야기해보자. 클래스가 클래스를 상속할때, 상위클래스로 올라가면 올라갈수록 클래스가 보편적(General)이게 되고 그렇기 때문에 더 추상적(Abstract)이게 된다. 어떠한 한 지점에 도달하게되면, 상위 클래스는 너무 보편적인 클래스가 되어버려 어떤 객체가 상속해도 될정도로 보편적인 기능들을 가지게 된다. 만일 우리가 회사 인사업무 프로그램을 설계한다면 Person 클래스는 매우 보편적인 객체가 되어버려, Employee, Manager, Executive, Boss, Intern 등의 어떤 클래스든 상속할수 있는 그런 객체가 될것이다. 자바 프로그램에서는 Object라는 클래스가 모든 클래스의 상위 클래스가 된다.

이런 상위클래스의 추상성과 보편성을 이야기하는 이유는, 어떤 분야의 객체들을 설계할 때, 그 객체들이 모두다 가지는 공통기능이 있을것이고, 이런 공통 기능들을 모은 최상위 수퍼클래스를 설계함으로 하위 클래스들의 부담을 줄일 수 있기 때문이다. 예를들어, 학교 인사업무 프로그램에서 Person 클래스는 모든 종류의 직원 클래스들과 학생 클래스들의 최상위 클래스가 된다. Person 클래스를 상속하는 Student, Employee 클래스, Employee 클래스를 상속하는 Professor, Manager, Executive 클래스, 뭐 이런식으로 계속 계층적 구조가 이어질것이다. 이 경우에 모든 직원 클래스들은 이름이란 데이터 필드를 가지게 되고, name 필드와 이에대한 acccesor, mutator 메소드들은 Person 클래스에 존재해도 잘 작동하게 된다. 그리고 모든 섭클래스마다 name 필드와 메소드들을 추가해줄 수고도 덜게된다.

그런데 만약에 Student, Employee, Professor 등의 클래스의 각 객체의 정보를 종합해 반환하는 getInfo 메소드가 필요할때, 이 getInfo 메소드를 Person 클래스에 추가해야될까? Person 클래스는 단순히 "이름" 정보만을 가지고 있는 클래스이고 getInfo 메소드가 반환해야하는 정보를 종합하기에는 가진 정보가 많이 부족한 클래스이다. 하지만 섭클래스들은 이 메소드를 무조건 가져야하고 우리는 최상위 수퍼 클래스인 Person 클래스에 이 메소드를 추가함으로써 Person 타입에서도 해당 메소드를 호출할수있게 해야할 필요가 있다. 물론 getInfo 메소드가 그냥 이름만을 반환하거나 빈 String 객체를 반환하도록 해도 된다. 하지만 더 좋은 방법이 있다. abstract 키워드를 이용해 해당 메소드를 추상메소드로 정의한다면, 메소드의 내용을 적지 않아도 Person 타입 변수에서 해당 메소드를 호출하는게 가능하다. 그리고 이런 abstract 메소드를 하나라도 가진 클래스는 abstract 클래스가 되게되고 abstract 키워드를 클래스 선언에 포함해야된다.


public abstract class Person {
 private String name;
 private int age;
        ... 
 public abstract void getInfo();
        ...
}

abstract 메소드가 섭클래스에서 정의될 메소드들을 미리 기안을 짜놓는다고 생각하면 된다. abstract 클래스를 상속할때, 섭클래스는 abstract 메소드들을 정의하거나 아니면 정의되지 않은 상태로 놔둘 수 있다. 하지만 정의하지 않은 abstract 메소드가 있다면 섭클래스도 abstract 클래스가 된다. 추상(abstract) 클래스에서는 인스턴스 생성이 불가능하다. 즉 우리는 Person 클래스의 생성자 함수를 호출해 Person 타입 객체를 생성하지 못한다. 물론 Person 클래스의 섭클래스 중 abstract 클래스가 아닌 클래스에서는 생성이 가능하고, 생성된 객체를 Person 타입으로 취급할 수도 있다.


Person p = new Person("Jason", 17); // 에러가 발생한다
Person s = new Student("Jenny", 21); // 정상 작동한다.
System.out.println(s.getInfo()); // 정상 작동한다.

이때 추상형(Abstract Type) 변수 s는 비추상클래스인 Student 클래스의 인스턴스를 참조하므로 정상 작동한다. 그리고 Student 클래스에서 getInfo 메소드도 정의했을테니 Person 타입 변수 s를 통해서 getInfo 메소드도 호출 가능하다. 만약 Person 클래스에 추상 메소드(Abstract Method) getInfo가 없었다면 호출이 불가능했을것이다.

댓글 없음:

댓글 쓰기