JAVA 입문 - 상속에서 클래스 생성과 형 변환
지난 글: [프로그래밍 언어/JAVA] - JAVA 입문 - 상속
하위 클래스가 생성될 때는 상위 클래스의 생성자가 먼저 호출된다. 상속 관계에서 클래스의 생성 과정을 보면 하위 클래스가 상위 클래스의 변수와 메서드를 사용할 수 있는 이유와 하위 클래스가 상위 클래스의 자료형으로 변환을 할 수 있는 이유를 이해 할 수 있다.
하위 클래스가 생성되는 과정
지난 글의 CustomerTest1 클래스를 살펴보면 VIPCustomer로 선언한 customerKim 인스턴스는 상속 받은 상위 클래스의 변수를 사용하였다. 변수를 사용할 수 있다는 것은 그 변수를 저장하고 있는 메모리가 존재한다는 것인데, VIPCustomer 클래스에는 해당 코드가 존재하지 않는다. Customer 클래스를 상속받았을 뿐이다. 여기서 상속된 하위 클래스가 생성되는 과정을 살펴보기 위해 Customer 클래스와 VIPCustomer 클래스 생성자에 출력문을 추가해보자.


이제 CustometTest2 클래스를 생성 후 실행하여 출력 결과를 보자.


출력 결과를 보면 상위 클래스인 Customer( ) 생성자가 먼저 호출되고 다음에 VIPCustomer( ) 생성자가 호출되는 것을 알 수 있다. 정리하면 상위 클래스를 상속받은 하위 클래스가 생성될 때는 반드시 상위 클래스의 생성자가 먼저 호출된다. 그리고 상위 클래스 생성자가 호출될 때 상위 클래스의 멤버 변수가 생성되는 것이다. 상위 클래스의 변수가 메모리에 먼저 생성되기에 하위 클래스에서도 이 값들을 모두 사용할 수 있다.
부모를 부르는 super 예약어
super 예약어는 하위 클래스에서 상위 클래스로 접근할 때 사용한다. super는 하위 클래스에서 상위 클래스를 가리킨다.하위 클래스는 상위 클래스의 주소(참조 값)를 알고 있다. 이 참조 값을 가지고 있는 예약어가 super이다. this가 자기 자신의 참조 값을 갖고 있는 것과 유사하다. 또 super는 상위 클래스의 생성자를 호출하는 데도 사용한다.
상위 클래스가 생성되는 과정
위의 CustomerTest2 클래스처럼 하위 클래스에서 생성자만 호출했는데 상위 클래스 생성자가 호출된 이유는 하위 클래스 생성자에서 super( )를 자동으로 호출해서이다. super( )를 호출하면 상위 클래스의 디폴트 생성자가 호출된다. 하위 클래스의 디폴트 생성자는 바이트 코드로 변환되기 전에 다음과 같이 코드가 자동 변경된다.

super 예약어로 매개변수가 있는 생성자 호출
만약 Customer 클래스를 생성할 때 고객 ID와 이름을 반드시 지정해야 한다고 가정하면 set( ) 메서드가 아닌 새로운 생성자를 만들어서 매개변수로 값을 전달해야한다. 다음과 같이 Customer 클래스에 새로운 생성자를 추가하고, 기존의 디폴트 생성자는 삭제 혹은 주석처리해보자.

이렇게 Customer 클래스의 디폴트 생성자를 없애고 새로운 생성자를 작성하면 Customer 클래스를 상속받은 VIPCustomer 클래스에서 오류가 발생한다.

이 오류는 묵시적으로 호출될 디폴트 생성자 Customer( )가 정의되지 않았기에, 반드시 명시적으로 다른 생성자를 호출해야 한다는 의미다.
Customer 클래스를 새로 생성할 때 고객 ID와 고객 이름을 반드시 지정하여 생성하기로 했으니 VIPSuctomer 클래스를 생성할 때도 이 값이 필요하다. 그리고 VIP 고객만을 위한 상담원 ID 까지 함께 지정해주자. 기존 VIPCustomer 클래스의 디폴트 생성자도 지우고 필요한 매개변수를 포함하는 새로운 생성자를 작성하자.

super 예약어는 상위 클래스 생성자를 호출하는 역할을 하며, 2행의 super(customerID, cistomerName); 문장으로 상위 클래스 생성자를 호출한다. super( )를 통해 Customer(int customerID, String customerName)상위 클래스 생성자를 호출하고 코드 순서대로 멤버 변수가 초기화된다. 상위 클래스 생성자 호출이 끝나면 VIPCustomer 하위 클래스 생성자의 내부 코드 수행이 마무리된다.
위에서 작성한 CustomerTest2 클래스에서 set( ) 메서드를 주석처리하거나 삭제한 후 VIPCustomer 생성자의 매개변수인 고객 ID, 고객 이름, 상담원 ID를 입력하고 실행하면 다음과 같이 출력된다.


VIP 등급 고객을 생성할 때는 상위 클래스 생성자를 먼저 호출한 후 하위 클래스 생성자의 코드 수행이 정상적으로 마무리된다.
상위 클래스의 멤버 변수나 메서드를 참조하는 super
상위 클래스에서 선언한 멤버 변수나 메서드를 하위 클래스에서 참조할 때도 super를 사용한다. 만약 VIPCustomer 클래스의 showVIPInfo( ) 메서드에서 상위 클래스의 showCustomerInfo( ) 메서드를 참조해 담당 상담원 ID를 추가로 출력하려고 할 때 다음과 같이 구현할 수 있다.

super예약어는 상위 클래스의 참조 값을 갖고 있으므로 위 코드처럼 고객 정보를 출력하는 메서드를 새로 구현하지 않고 super.shoCustomerInfo( )처럼 사용해 상위 클래스의 메서드를 활용할 수 있다. 물론 위 코드의 showVIPInfo( ) 메서드에서는 굳이 super를 사용하지 않아도 상위 클래스의 메서드가 잘 호출된다. 아직은 배우지 않았지만 하위 클래스가 상위 클래스와 동일한 이름의 메서드를 구현하는 경우도 있다고 한다. 이런 경우에 하위 클래스에서 같은 이름의 상위 클래스 메서드를 가리킬 때는 super.showCustomerInfo( )라고 해줘야 한단다.
상위 클래스로 묵시적 클래스 형 변환
상속을 공부하면서 이해해야할 중요한 관계가 클래스 간의 형 변환이다. 예로 내가 만든 Customer 상위 클래스와 VIPCustomer 하위 클래스를 보면 VIPCustomer 클래스가 기능이 더 많다. 이유는 상속받은 클래스는 상위 클래스의 기능을 모두 사용할 수 있고, 추가로 더 많은 기능을 구현하기 때문이다.

따라서 VIPCustomer는 VIPCustomer형이면서 동시에 Customer형이기도 하다. VIPCustomer 클래스로 인스턴스를 생성할 때는 이 인스턴스의 자료형을 Customer로 형 변환 하여 선언할 수 있다. VIPCustomer 클래스는 Customer 클래스를 상속받았기 때문이다. 하지만 그 반대의 경우는 안된다. Customer는 VIPCustomer의 기능을 모두 갖고 있는 것이 아니기 때문이다. 정리하자면 모든 하위 클래스는 상위 클래스로 형 변환할 수 있지만 반대는 성립되지 않는다.
형 변환된 vc가 가리키는 것

위 코드의 Customer vc = new VIPCustomer( ); 에서 형 변환된 vc 참조 변수가 가리키는 것은 Customer 클래스의 멤버뿐이다. 이유는 클래스의 자료형이 Customer로 한정되었기에 클래스가 형 변환 되었을 때는 선언한 클래스형에 기반하여 멤버 변수와 메서드에 접근할 수 있기 때문이다.
참고 서적: 자바 프로그래밍 입문 - 박은종