사전적 의미로는 일정한 친족 관계가 있는 사람 사이에서 재산상의 권리·의무 일체를 이어받는 일을 의미하는데요. 객체 지향 개념에서의 상속이란 기존의 클래스에 기능을 추가하거나 재정의하여 새로운 클래스를 정의하는 것을 의미합니다.
상속을 이용하면 굳이 중복되는 코드를 작성할 필요 없이 상위 클래스(부모 클래스) 로부터 물려받은 멤버 요소와 새로운 사용자 정의 멤버 요소를 기반으로한 클래스의 생성이 가능하다는 점에서 아주 편리한 기능 중 하나인데요.
해당 기능을 사용해 자식 클래스에서 부모 클래스에 상속을 받을 경우 extends
키워드를 작성하면 되며, 하나의 자식은 하나의 부모로부터만 상속을 받을 수 있다는 점을 유의하시기 바랍니다.
(후에 설명할 인터페이스를 이용하면 다중 상속이 가능해 집니다.)
public class 부모클래스(슈퍼클래스) { 이하 내용ㆍㆍㆍ } public class 자식클래스(자식클래스) extends 부모클래스{ 이하 내용ㆍㆍㆍ }
상속은 앞서 말씀드린대로 extends
키워드를 사용해 상속 받을 상위 클래스를 지정하는 것으로 쓰임이 시작되는데요.
상위 클래스에서 생성자는 갖고 있으나 매개변수를 가지고 있지 않은 생성자가 있는 경우, 또는 생성자가 생략되어 있는 경우 하위 클래스에서는 super
키워드를 생략 가능합니다.
그러나 상위 클래스에서 매개변수를 받고 있다면 super
키워드 안에 상위 클래스의 생성자에서 받고 있는 매개변수를 작성해 주어야 합니다.
// 부모 클래스 class People { String nationality; // 생성자 People(String nationality) { this.nationality = nationality; } void displayNationality() { System.out.println("Nationality: " + nationality); } } // 자식 클래스가 부모 클래스를 상속 class Korean extends People { String language; // 생성자 Korean(String nationality, String language) { super(nationality); // 부모 클래스의 생성자 호출 this.language = language; } void displayLanguage() { System.out.println("Language: " + language); } } public class Main { public static void main(String[] args) { // 자식 클래스의 객체 생성 Korean korean = new Korean("Korean", "Korean"); // 부모 클래스의 메서드 호출 korean.displayNationality(); // 자식 클래스의 메서드 호출 korean.displayLanguage(); } }
앞서 설명한 메서드의 오버로딩 에서도 알 수 있듯이 반환 타입이나 매개 변수, 메서드 이름은 동일하게 두고 (변경 불가능) 안에 있는 코드 실행 부분만 다르게 정의할 수 있습니다.
상속을 받은 클래스 에서는 상위 클래스로부터 메서드를 상속 받을 때 반환 타입이나 매개변수의 수, 순서, 타입이 같더라도 상속 받은 메서드를 독자적으로 재정의 하는 것이 가능한데, 이를 오버라이딩
이라고 합니다.
이 오버라이딩은 재정의하고자 하는 상속 메서드의 윗부분에 @Override
어노테이션을 작성해주면 됩니다.
class People { String nationality; // 생성자 People(String nationality) { this.nationality = nationality; } void displayNationality() { System.out.println("Nationality: " + nationality); } } // 자식 클래스가 부모 클래스를 상속 class Korean extends People { String language; // 생성자 Korean(String nationality, String language) { super(nationality); // 부모 클래스의 생성자 호출 this.language = language; } void displayLanguage() { System.out.println("Language: " + language); } // displayNationality 메서드를 오버라이딩 @Override void displayNationality() { // 오버라이딩된 내용으로 재정의 System.out.println("Korean Nationality: " + nationality); } } public class Main { public static void main(String[] args) { // 자식 클래스의 객체 생성 Korean korean = new Korean("Korean", "Korean"); // 부모 클래스의 메서드 호출 korean.displayNationality(); // 자식 클래스의 메서드 호출 korean.displayLanguage(); } }
참고로 재정의된 부모 메서드의 원본을 호출하고자 할 경우 super.부모메서드
형식으로 호출이 가능합니다.
@Override void displayNationality() { if(nationality != "kroean"){ super.displayNationality(); }else{ System.out.println(Korean Nationality: " + nationality) }
이러한 오버라이딩을 이용해 상위 클래스의 메서드 (기능)를 하위 클래스가 받아와서 재정의 함으로서 상황에 맞춰 메서드를 커스터마이징 할 수 있는 유연성과 유지보수성을 총칭 다형성
이라고 부르는 것이죠.