본문 바로가기
공부/자바 (Java)

[Java] 상속(Inheritance), 메서드 오버라이딩, 다형성, 다운캐스팅, 업캐스팅

by Lagooni 2021. 12. 21.

상속이란? 

새로운 클래스를 정의할 때 이미 구현된 클래스를 상속 받아서 속성이나 기능이 확장되는 클래스를 구현하는 것.

상위클래스는 하위클래스보다 일반적인 개념과 기능을 가진다.

하위클래스는 상위클래스보다 구체적인 개념과 기능을 가진다.

화살표의 방향이 반대같아 보이지만 하위클래스가 상위클래스를 가져오는 것

자바는 Single Inheritance만 지원하기 때문에 extends 뒤에는 단 하나의 class 만 사용할 수 있다.

class B extends A{
}

public class Customer {

    protected int customerID;
    protected String customerName;
    protected String customerGrade;
    int bonusPoint;
    double bonusRatio;
 }
public class VIPCustomer extends Customer{

    double salesRatio;
    private int agentID;

    public VIPCustomer(){
        customerGrade = "VIP";
        bonusRatio = 0.05;
        salesRatio = 0.1:
    }
}

부모클래스에서 상속받기위해서는 private는 불가능하다. 상속받는 하위클래스가 있다면 상위클래스에서 protected로 선언한다.

protected는 외부클래스에서는 private기능을하며, 하위클래스에서는 public의 기능을 하는 키워드이다. 

예약어 정리

상속은 언제 사용할까?

IS-A관계 (is a relationship : inheritance)

  • 일반적인 개념과 구체적인 개념의 관계
  • 상위 클래스(일반적인 개념; ex: 포유류), 하위클래스(구체적인 개념; ex: 사람, 원숭이)

HAS-A관계 (composition)

  • 한 클래스가 다른 클래스를 소유한 관계 코드 재사용의 한 방법
  • ex) 학생 클래스가 과제 클래스를 포함하는 관계

하위클래스가 생성되는 과정

하위클래스가 생성 될 때 상위클래스가 먼저 생성된다. (자식보다 부모먼저)

상위클래스의 생성자가 호출되고 하위클래스의 생성자가 호출된다.(부모클래스 생성자 먼저)

하위 클래스에서 상위 클래스의 생성자를 호출하는 코드가 없는 경우 컴파일러는 상위 클래스 기본 생성자를 호출하기 위한 super()를 추가한다.(자동으로 호출함)

super()로 호출되는 생성자는 상위 클래스의 기본 생성자이다.

만약 상위 클래스의 기본 생성자가 없는 경우(매개 변수가 있는 생성자만 존재하는 경우) 하위 클래스는 명시적으로 상위 클래스의 생성자를 호출해야 한다.

 

상위클래스로의 묵시적 형 변환 (업 캐스팅)

상위(부모)클래스 형으로 변수를 선언하고 하위 클래스 인스턴스를 생성할 수 있다.

하위클래스는 상위 클래스의 타입을 내포하고 있으므로, 상위클래스로 묵시적 형변환이 가능하다.

상속관계에서 모든 하위클래스는 상위 클래스로 묵시적 형 변환이 가능하지만 역은 성립하지 않는다.

그렇다면 Coutomer vc = new VIPCustomer()에서 vc가 가리키는 것은 뭘까?

VIPCustomer() 생성자의 호출로 인스턴스는 모두 생성되었지만, 타입이 Customer이므로 접근할 수있는 변수나 메서드는 Customer에 있는 변수, 메서드만 사용이 가능하다.


오버라이딩(overriding)

상위 클래스에서 정의된 메서드의 구현 내용이 하위 클래스에서 구현할 내용과 맞지 않는 경우 하위클래스에서 동일한 메서드를 재정의 할 수 있다. (덮어쓰기 같은 기능)

애노테이션(Annotation)

재정의된 메서드라는 의미로 선언부가 기존의 메서드와 다른 경우 에러 발생

애노테이션은 컴파일러에게 특정한 정보를 제공하는 역할이다.


Customer의 calcPrice함수
VIPCustomer의 calcPrice오버라이딩

업 캐스팅을 통해 묵시적 형변환이 가능하다. 그렇다면 기존 함수가 오버라이딩 된 이 경우는 어떨까?

Customer vc = new VIPCustomer();
vc.calcPrice(1000);

VIPCustomer() 생성자의 호출로 인스턴스는 모두 생성되었지만, 타입이 Customer이므로 접근할 수있는 변수나 메서드는 Customer에 있는 변수, 메서드만 사용이 가능하다고 했지만. 자바에서는 항상 인스턴스 메서드가 호출되기 때문에 오버라이딩된 calcPrice가 호출된다.  (C++에서  가상상속 virtual이 사용되는것과 같다.)


가상 메서드(Virtual Method)

메서드의 이름과 메서드 주소를 가진 가상 메서드 테이블에서 호출될 메서드의 주소를 참조한다.


다형성(Polymorphism)

하나의 코드가 여러 자료형으로 구현되어 실행되는 것으로서 같은 코드에서 여러 실행 결과가 나온다.

정보은닉, 상속과 더불어 객체지향 프로그래밍의 가장 큰 특징 중 하나이다. (유연성, 재활용성, 유지보수성에 기본이 되는 특징이다.)

자바에서는 다형성을 위해 부모 클래스 타입의 참조 변수로 하위 클래스 타입의 인스턴스를 참조할 수 있도록 하고있다.(업 캐스팅)

 

다형성 구현 방법

클래스의 상속이나 인터페이스를 구현하는 자식 클래스에서 메서드를 재정의(오버라이딩) 하고 자식 클래스를 부모 타입으로 업캐스팅한다. 그리고 부모 타입의 객체에서 자식 멤버를 참조하여 다형성을 구현한다.

class Animal{
    public void move(){
        System.out.println("동물이 움직입니다.");
    }
}
class Human extends Animal{
    @Override
    public void move() {
        System.out.println("사람이 두발로 걷습니다.");
    }
}
class Tiger extends Animal{
    @Override
    public void move(){
        System.out.println("호랑이가 네 발로 뜁니다.");
    }
}
class Eagle extends Animal{
    @Override
    public void move() {
        System.out.println("독수리가 하늘을 날아갑니다.");
    }
}
public class AnimalTest {
    public static void main(String[] args){
        Animal hAnimal = new Human(); //업캐스팅
        Animal tAnimal = new Tiger(); //업캐스팅
        Animal eAnimal = new Eagle(); //업캐스팅

        AnimalTest test = new AnimalTest();
        test.moveAnimal(hAnimal);
        test.moveAnimal(tAnimal);
        test.moveAnimal(eAnimal);
    }
    public void moveAnimal(Animal animal){ //Animal객체 하나로 26~28번 라인에서 생성한 인스턴스들이 함수를 같이 사용할 수 있다.
        animal.move();
    }
}

다형성의 사용으로 인한 장점?

다양한 여러 클래스를 하나의 자료형(상위 클래스)으로 선언하거나 형변환 하여 각 클래스가 동일한 메서드를 오버라이딩 한 경우, 하나의 코드가 다양한 구현을 실행할 수 있다.

유사한 클래스가 추가되는 경우 유지보수에 용이하고, 각 자료형 마다 다른 메서드를 호출하지 않으므로 코드에서 많은 if문을 줄일 수 있다.


다운캐스팅

묵시적으로 상위클래스 형변환된 인스턴스가 원래 자료형(하위클래스)으로 변환되어야 할 때 다운캐스팅이라고 한다.

하위 클래스로의 형 변환(다운캐스팅)은 명시적으로 되어야한다.

Customer vc = new VIPCustomer();	//묵시적 형변환
VIPCustomer vCustomer = (VIPCustomer)vc;	//명시적 형변환

 

다운캐스팅은 강제 형 변환한 객체가 원래의 자료형(하위클래스)이 아니라면 코드상에서 에러로 표시되지 않는다.

hAnimal의 하위클래스는 Human인데 맞지않는 Eagle로 다운캐스팅해도 에러를 표시하지 않는다.
결과는 당연히 에러

이런 경우를 예방하기 위해 instanceof 연산자를 사용한다.

instanceof연산자는 객체가 어떤 클래스인지, 어떤 클래스를 상속받았는지 확인하는데 사용한다. true/false로 반환

instanceof를 사용한 경우

 

댓글