Java - 상속

Lee·2020년 12월 25일
0

Java

목록 보기
3/9
post-thumbnail

자바에서 지원하는 상속에 대해 공부해보자 🤔

  • 자바 상속의 특징
  • super 키워드
  • 메소드 오버라이딩
  • 다이나믹 메소드 디스패치
  • 추상 클래스
  • final 키워드
  • Object 클래스

상속(Inheritance)이란? 🤔

현실세계에서의 상속

  • 사람의 사망에 의한 재산 및 신분상의 지위의 포괄적인 승계를 말한다.

객체 지향 프로그래밍의 상속

  • 클래스의 상태 및 동작을 다른 클래스에서 동작 시킬 수 있다는 뜻이다.

상속을 사용하는 이유는? 🤔

  • 기존의 클래스를 재사용하기 때문에 적은 양으로 새로운 클래스를 작성할 수 있다.
  • 코드를 공통적으로 관리할 수 있기 때문에 코드의 추가 및 변경이 매우 용이하다.
  • 코드의 재사용성을 높이고 코드의 중복을 제거할 수 있어 프로그램의 생산성과 유지보수에 크게 기여한다.

상속을 사용하는 방법

  • extends 키워드를 사용하여 상속할려는 클래스 이름을 작성하면 된다.
class Child extends Parent {

}

관계

  • Child 클래스와 Parent 클래스는 서로 상속 관계에 있으며, 상속해주는 클래스(Parent 클래스)를 부모 클래스 혹은 상위 클래스라고 부르며, 상속받는 클래스(Child 클래스)를 자식 클래스 혹은 하위 클래스라고 부른다.
  • 하위 클래스는 상위 클래스의 모든 멤버, 메소드를 상속받기 때문에 하위 클래스는 상위 클래스를 포함한다고 할 수 있다.
    만약 Parent 클래스에 age라는 정수형 변수를 선언했다고 가정하에 상속 관계를 다시 살펴보면
ParentChild
ageage
  • 하위 클래스인 Child 클래스 또한 상속받기 때문에 Child 클래스에선 자동적으로 age라는 멤버 변수를 사용할 수 있다.

7, 10줄은 Child 클래스 안에 child_age라는 변수를 선언하여 호출한 것이고
23, 26줄은 상속받은 Parent 클래스 안에 age라는 변수를 호출하여 사용하는것이다.

invokespecial은 생성자, private 메소드, 슈퍼 클래스의 메소드를 호출할 때 사용한다.
아직 미숙하지만 나의 생각으론 Parent 클래스의 생성자를 호출한 객체를 만들어 자연스럽게 age변수를 사용할 수 있는 것 같다.

  • 반면 Child 클래스에 school()이라는 메소드를 선언해도 Parent 클래스에는 아무런 영향이 없다.
ParentChild
ageage, school()

Child 클래스의 생성자만 호출한 후 school()이라는 인스턴스 메소드를 호출한다.
Parent 클래스에는 아무런 영향이 가지 않는다는 의미기도 하다.

사실 아직 무슨 의미인지 눈에 잘 안들어온다..바이트 코드에 대해서 좀 더 공부해보고싶다 ㅎㅎ.. 🤣

  • 상속을 통해 중복된 코드를 줄일 수 있다.
    Parent 클래스를 상속받는 Child2 클래스를 하나 더 생성해서 중복된 코드를 줄일 수 있다는 것을 확인해보자

  • Parent.age값을 변경하기 전

public class Parent {

    int age = 30;

}
public class Test {
    public static void main(String[] args) {

        /*
            단순한 예시로 부모님의 연세가 어떻게 되시니?라고 물어보면
            부모님의 자식들은 동일하게 **살 입니다. 라고 대답할것이다.
         */
        System.out.println("Parent의 age가 어떻게 되니??");
        System.out.println("아 저희 Parent의 age는 " + new Child().age + "살 입니다.");
        System.out.println("아 저희 Parent의 age는 " + new Child2().age + "살 입니다.");

    }
}

output
Parent의 age가 어떻게 되니??
아 저희 Parent의 age는 30살 입니다.
아 저희 Parent의 age는 30살 입니다.

만약 해가 바뀌어 부모님의 연세가 바뀌었다고 가정해보자

Parent를 상속받는 Child, Child2 클래스에 직접 가서 age값을 수정해도 되지만 만약 Parent를 상속받는 클래스가 100개 이상이고, age값을 수정하는 일이 복잡하다고 가정해보자. 그럼 age값을 수정하는 행위를 100번 해야하고, 과정속에서 에러가 발생할 확률이 높아질 것이다. 상속을 통해 Parent.age라는 변수가 자연스럽게 하위 클래스에 선언된다는 특징을 알기 때문에 상위 클래스 즉 Parent의 값만 수정해주면 이를 상속받는 클래스들에 있는 age값은 자연스럽게 변한다.

  • Parent.age값을 변경한 후
public class Parent {

    int age = 31;

}
public class Test {
    public static void main(String[] args) {

        /*
            단순한 예시로 부모님의 연배가 어떻게 되시니?라고 물어보면
            부모님의 자식들은 동일하게 **살 입니다. 라고 대답할것이다.
         */
        System.out.println("Parent의 age가 어떻게 되니??");
        System.out.println("아 저희 Parent의 age는 " + new Child().age + "살 입니다.");
        System.out.println("아 저희 Parent의 age는 " + new Child2().age + "살 입니다.");

    }
}
output
Parent의 age가 어떻게 되니??
아 저희 Parent의 age는 31살 입니다.
아 저희 Parent의 age는 31살 입니다.

단일상속

  • 자바에선 단일 상속만을 허용한다. 즉 하나 이상의 클래스로부터 상속을 받을 수 없다는 이야기다.
class Child extends Parent, GrandParent {
	// 이와 같은 코드는 다중 상속이므로 자바에선 불가능하다.
}

다중상속을 이용하면 여러 클래스로부터 상속을 받을 수 있다는 장점이 있지만 그 만큼 객체와의 관계가 복잡하다는 단점이 있다.

만약 Parent, GrandParent에 문자열 타입에 주소를 의미하는 address 변수가 있다고 가정해보자

class GrandParent {
	String address = "";
}
class Parent {
	String address = "";
}

다중상속이 된다는 가정하에 코드를 짜보자 Parent, GrandParent 둘 다 상속받는 Child클래스를 만들어보면

class Child extends Parent, GrandParent {

    public void school() {
        System.out.println("학교에 간다.");
    }

    public static void main(String[] args) {
		System.out.println("우리집은 ? " + new Child().address);
    }
}

위 코드는 물론 컴파일 에러가 발생하기 때문에 실행조차 되지 않을 뿐더라 만약 실행이 된다고 해도 컴파일러 입장에선 addressParent클래스인지, GrandParent클래스를 의미하는지 모를 것이다.

Object 클래스

  • Object클래스는 모든 클래스 상속계층도의 제일 위에 위치하는 상위클래스이다.
  • 공식 문서상에서도 Object클래스는 클래스 계층의 루트이며, 모든 클래스에는 Object객체가 슈퍼 클래스로 있다.

다른 클래스로부터 상속을 받지 않는 Parent클래스를 정의하였다고 했을때, 컴파일 하면 extends Object 키워드가 붙는다..는데..?

public class Parent {


}

참고한 문서에 의하면 아래와 같이 바이트코드로 분석했을때 extends java.lang.Object가 붙는다.

근데 내가 한거에는 왜 없즤....동일하게 SimpleProgram 클래스 만들어서 했는데..뭐지..🤔
조금 더 자료를 찾아봐야할 것 같다.

오버라이딩(Overriding)

  • 오버라이딩이란?
    사전적인 의미는 ~위에 덮어쓰다(overwrite) 또는 ~에 우선하다. 라는 의미를 가지고 있다.
    상속받은 메소드의 내용을 변경하는 것이다.

왜 오버라이딩을 사용하는가?

  • 상위 클래스의 메소드가 하위 클래스에서 충분한 기능을 제공하지 못하거나, 부족할 경우 상위 클래스로부터 상속받은 메소드를 재정의 한다.

  • 이해하기 편하게 비유를 한다면, 만약 부모님으로 부터 재산을 상속받았다는 상상을 한번 해보자 재산을 상속받은 자식들은 이 재산을 그대로 둘까? 그대로 둘 가능성은 거의 희박하다. 그 만큼 현실을 살아가면서 상속받은 재산에 대해 자식들이 사용하거나 변경할 수 있기 때문이다.

  • 자바에서도 마찬가지이다. 상위 클래스에서 상속받은 메소드를 본인에 입맞게 맞게 튜닝한다고 생각하면 될 것 같다 💡

class Car {
    private boolean engine;

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;

    public void showState() {
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}

public class Test {
    public static void main(String[] args) {

        Audi audi = new Audi();
        audi.startEngine(true);
        audi.setQuattro(true);
        audi.showState();
    }
}

출력문
현재 4륜 시스템이 켜져있는가? :true

여기서 Audi클래스는 Car클래스를 상속받았으므로 Car 클래스의 메소드인 startEngine()호출할 수 있다.
또한 setQuattro()메소드를 통해 4륜 시스템의 작동여부를 설정할 수 있으며 showState()메소드를 호출함으로써 현재 Audi클래스의 상태를 알 수 있다. 하지만 Car클래스에도 showState()메소드가 있는데 호출이 되지 않았다. 그 이유는 Audi클래스에서 showState()메소드를 오버라이딩 했기 때문에 재정의된 메소드로 호출된 것이다.

  • 그러면 Car 클래스의 showState 메소드는 Audi 클래스에서 영영 호출할 수 없는 것인가..? 🤔
    super 키워드를 사용하면 가능!💡

오버라이딩을 하기 위한 조건

  • 오버라이딩은 메소드의 내용만 새로 작성하는 것이므로 메소드의 선언부(반환타입, 메소드명, 파라미터 갯수)가 일치해야 한다.
  • 이름이 같아야한다.
  • 매개변수(갯수, 데이터 타입, 순서)가 같아야 한다.
  • 리턴타입이 같아야 한다.

Car 클래스에선 showState()메소드를 호출했을 때 엔진의 시동여부를 판단하지만, 이를 상속받는 Audi 클래스에선 4륜 시스템의 작동여부를 판단하는 기능으로 재정의하여 사용한다.

super

  • super키워드는 하위 클래스에서 상위 클래스로부터 상속받은 멤버(변수, 메소드)를 참조하는데 사용되는 참조 변수이다.
  • 클래스의 멤버변수와 메소드 안에 지역변수의 이름이 동일할 때 this키워드를 사용하는것 처럼 상속받는 멤버와 자신의 클래스 내에 이름이 동일한 경우 super키워드를 작성한다.
  • 쉽게 이해하자면 상위 클래스에 있는 멤버를 호출하기 위해 사용하는 키워드이다.
class Car {
    private boolean engine;

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}

public class Test {
    public static void main(String[] args) {

        Audi audi = new Audi();
        audi.startEngine(true);
        audi.setQuattro(true);
        audi.showState();
    }
}
출력물
현재 엔진의 시동이 걸려있는가? : true
현재 4륜 시스템이 켜져있는가? :true

super()

  • 상위 클래스의 생성자를 호출하는데 사용된다.

사용하는 이유

  • 하위 클래스의 인스턴스를 생성하면 상위 클래스와 하위 클래스가 합쳐진 상태로 인스턴스가 만들어진다. 이때 상위 클래스에 대한 초기화 작업이 필요한 경우가 있는데, 이때 하위 클래스에서 상위 클래스에 생성자를 호출해야 한다.
class Car {
    private boolean engine;
    public String color;

    public Car(String color) {
        this.color = color;
    }

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;

    public Audi() {
        super("black");
    }

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}

public class Test {
    public static void main(String[] args) {

        Audi audi = new Audi();
        audi.startEngine(true);
        audi.setQuattro(true);
        audi.showState();
    }
}
  • Audi클래스의 생성자 호출을 통해 객체로 만들 때 상위 클래스인 Car클래스에 생성자를 super()키워드를 통해서 호출하여 차량의 색상을 정한다.

abstract

  • 추상이란?
    핵심적인 개념 또는 기능을 간추려 내는 것을 말한다.

abstract class

  • 추상클래스란?
    핵심적인 개념 또는 기능을 간추려 놓은 클래스이다.

한가지 예를 들면

자동차를 만드는 제조사는 여러개가 있다. A제조사, B제조사, C제조사는 각 제조사의 특징대로 자동차를 만든다. A자동차는 4륜 시스템을 도입하여 자동차가 달릴 때 안정감을 줄 수 있도록 만들고, B제조사는 후륜 구동 방식을 채택하여 달릴 때 운전자에게 재미난 요소를 제공하게끔 만들고, C제조사는 달릴 때 방지턱, 요철에 대한 충격 흡수를 잘할 수 있는 장치를 만들어 운전자에게 편안함을 제공해준다.

여기서 자동차 제조사들 별로 공통적인 특징을 가지고 있는데 이 특징이 달린다라는 특징이다. 달린다는 특징을 가지고 있는 Car클래스 만든 후 각 제조사별로 이 Car클래스를 상속받아 차를 만들면 어떨까?? 달린다는 본질은 달라지지 않고 각 제조사의 특징을 잘 살려서 자동차를 만들 수 있을 것이다.

여기서 달린다는 기능을 가지고 있는 Car클래스가 추상 클래스이고, 이 Car클래스를 상속받아 각 제조사별 자동차를 만들어 내는 클래스가 실체 클래스이다.

즉 실체 클래스는 실체 말 그대로 인스턴스를 만들 수 있는 클래스이고
추상클래스는 인스턴스를 만들지 못하지만, 실체 클래스에 기반이 되는 클래스이다.

그렇다면 왜 추상클래스를 사용할까? 🤔

여기서 나온 예시들은 이해를 돕기 위한 예시일뿐 실제는 아니다 🚀

  • 공통된 필드와 메소드를 통일할 목적
    많은 자동차 제조사들이 엑셀레이터에 대해 제각기 다른 이름을 가지고 만들면 어떻게 될까? 아마 전세계의 자동차 회사들이 엑셀레이터의 이름을 다르게 만들것이다. 여기까지는 문제가 없지만 만약 차를 이용하는 사용자, 수리하는 정비공에게 많은 혼란을 줄 것이다. 이러한 이유로 인해 규격이라는 하나의 규칙을 만들어 이 규격을 베이스로 자동차 회사들은 기본적인 장치들에 대해 이름을 통일하여 자동차를 만든다.

혼자 개발할땐 문제가 없지만, 실제 개발시 필드와 메소드 이름을 통일하여 여러 사람이 개발을 할 때 앞으로 가기를 누군가는 moveForward()라고 표현할 것이고, 또 누군가는 goForward()라고 부를 것이다. 때문에 추상 클래스를 사용하여 미리 정의해놓은 필드명와 메소드를 이용하여 실체를 구현한다.

  • 실체클래스 구현시, 시간절약
    새로운 자동차 제조사인 V라는 제조사가 탄생했다고 가정해보자. 이 제조사는 트럭을 만드는 제조사이다. 차체는 클 뿐 자동차의 기본적인 요소는 동일하다. 하지만 처음부터 만들다 보니 바퀴, 내연기관, 트렁크, 미션 등..구현하는데 기본적인 기능들만 해도 시간이 오래 걸린다.

하지만 자동차의 기본요소를 규격해 놓은 상태에서 트럭을 만든다고 하면? 차체에 대한 부분만 개발하면 되기 때문에 만드는데 시간을 단축시킬 수 있을 것이다. 실제 우리가 개발할 때도 규격해놓은 추상클래스만 있으면 기본적인 필드와 메소드에 대해 생각할 필요 없이 구현하는데만 집중할 수 있어 개발 시간을 단축시킬 수 있다.

  • 규격에 맞는 실체클래스 구현
    공통된 필드와 메소드를 통일할 목적, 시간절약 위에서 설명했지만 자동차를 만드는 제조사에서 아무리 자기 스타일대로 자동차를 만든다고 하지만 결국 규격안에서 자기 스타일대로 만들뿐, 규격을 벗어난 상태로 상품을 개발해선 안된다. 왜냐하면 차는 혼자 만들지 않기 때문에 서로 약속한 규격안에서 개발을 해야한다.

여기서 추상클래스(규격)을 상속받는 실체클래스(자동차 제조사)는 반드시 추상메소드에 정의 되어있는 메소드를 재정의(오버라이딩)해서 실체클래스에서 작성해야한다. 그렇지 않으면 컴파일 에러가 발생하여 실행조차 되지 않는다.

abstract class Car {

    abstract void airbag(); // 에어백 기능
    abstract void transmission(); // 미션 기능
}

class Audi extends Car {
    private boolean quattro;

    void airbag() {
        System.out.println("에어백을 운전석에 장착했습니다."); // 추상 메소드를 구현
    }

    void transmission() {
        System.out.println("ZF사의 8단 미션을 장착했습니다."); // 추상 메소드를 구현
    }

    public void showState() {
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}

public class Test {
    public static void main(String[] args) {

        Audi audi = new Audi();
        audi.airbag();
        audi.transmission();
        audi.setQuattro(true);
        audi.showState();
    }
}

출력물
에어백을 운전석에 장착했습니다.
ZF사의 8단 미션을 장착했습니다.
현재 4륜 시스템이 켜져있는가? :true

final ✍️

  • '마지막의' 또는 '변경될 수 없는' 의미를 지님
  • 변수에 사용하면 변경할 수 없는 상수가 되고, 메소드에 사용하면 오버라이딩을 할 수 없고, 인자값에 사용할 경우 인자값의 변경이 불가능하고, 클래스에 사용하면 상속이 불가능한 상태가 된다.
class Car {
    private boolean engine;
    public final boolean airbag = true;
    public String color;

    public Car(String color) {
        this.color = color;
    }

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;

    public Audi() {
        super("black");
    }

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}

public class Test {
    public static void main(String[] args) {

        final Audi audi = new Audi();
        audi.setQuattro(true);
        audi.showState();
    }
}
  • final 클래스

//final 클래스
final class Car {
    private boolean engine;
    public final boolean airbag = true;
    public String color;

    public Car(String color) {
        this.color = color;
    }

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

// Car클래스가 Final로 정의되었기 때문에 상속이 불가능하다.
class Audi extends Car {
    private boolean quattro;

    public Audi() {
        super("black");
    }

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}
  • Car클래스가 final로 정의되었기 때문에 이를 Audi클래스에선 Car클래스를 상속받을 수 없다고 에러 창이 나온다.

  • final 메소드

class Car {
    private boolean engine;
    public final boolean airbag = true;
    public String color;

    public Car(String color) {
        this.color = color;
    }

    public final void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;

    public Audi() {
        super("black");
    }

    // 메소드 오버라이딩 불가능
    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }
}
  • Car클래스에 showState()메소드를 final로 정의한 상태에서 상속받은 Audi클래스에서 오버라이딩을 하면 아래와 같은 에러가 난다.

  • 메소드의 인자값이 final을 사용할 경우

class Audi extends Car {
    private boolean quattro;
    String tire = "";

    public Audi() {
        super("black");
    }

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }


    public void setTire(final String tire) {
        tire = "한국타이어";
        this.tire = tire;
    }
}

public class Test {
    public static void main(String[] args) {

        final Audi audi = new Audi();
        audi.setQuattro(true);
        audi.setTire("미쉐린");
        audi.showState();
    }
}

다이나믹 메소드 디스패치 ✍️

  • 메소드 디스패치 : 어떤 메소드를 호출할지 결정하여 실제로 실행시키는 과정을 의미함

메소드 디스패치의 종류로는 Static Dispatch, Dynamic Dispatch가 있다.

  • Static Method Dispatch
    컴파일 시점에서 컴파일러가 특정 메소드를 호출할 것이라는걸 명확하게 알고있는 경우이다.
    런타임(실행 시점)이 되지 않아도 미리 결정하는 개념이다.

컴파일 시 생성된 바이트 코드에도 이 정보가 남아있다.

함수를 오버로딩하여 사용하는 경우, 인자의 타입이나 리턴타입 등에 따라 어떤 메소드가 호출될 지 명확하기 때문에 이러한 경우도 '미리 알 수 있다'라고 할 수 있다.

위에서 작성한 SimpleProgram에 바이트 코드로 예시를 들어보자

빨간줄로 표시된 줄이 System.out.println() 함수를 호출하는 것이며, 런타임 시점이 되지 않아도 미리 결정될 수 있기에 Static Method Dispatch에 해당한다.

  • Dynamic Method Dispatch

Static Method Dispatch와는 다르게 런타임 시점이 되서야 알 수 있는 메소드들이 여기에 해당한다. 좀 더 쉽게 이야기하자면 상속, Interface 혹은 Abstract Class에서 정의된 Method를 오버라이딩하여 호출할 경우 해당된다.

위에서 작성한 Car클래스를 예시로 들면

Audi audi = new Audi()는 Static Method Dispatch에 해당하고
Car car = new Audi();로 변경하여 객체를 생성하면 Dynamic Method Dispatch가 된다

class Car {
    private boolean engine;
    public final boolean airbag = true;
    public String color;

    public Car(String color) {
        this.color = color;
    }

    public void showState() {
        System.out.println("현재 엔진의 시동이 걸려있는가? : " + engine);
    }
    public void startEngine(boolean engine) {
        this.engine = engine;
    }
}

class Audi extends Car {
    private boolean quattro;
    String tire = "";

    public Audi() {
        super("black");
    }

    public void showState() {
        super.showState();
        System.out.println("현재 4륜 시스템이 켜져있는가? :" + quattro);
        System.out.println("현재 차량의 색상은? : " + color);
    }

    public void setQuattro(boolean quattro) {
        this.quattro = quattro;
    }


    public void setTire(String tire) {
        tire = "한국타이어";
        this.tire = tire;
    }
}

public class Test {
    public static void main(String[] args) {

        Audi audi = new Audi();
//        audi.setQuattro(true); // static method dispatch
//        audi.setTire("미쉐린");
//        audi.showState();

        Car car = new Audi();
        car.showState();
    }
}

출력물
현재 엔진의 시동이 걸려있는가? : false
현재 4륜 시스템이 켜져있는가? :false
현재 차량의 색상은? : black

위 예제 코드와 같이 런타임시 상위 클래스 타입으로 객체를 생성한 후 오버라이딩된 메소드를 호출하는 것을 Dynamic Method Dispatch라고 한다.

바이트 코드를 보면 조금 더 이해가 쉽다.

Car.showState()메소드를 호출할뿐 그 외 메소드 호출은 Dynamic Method 이므로 바이트 코드기록에 남지 않는다.

🧾 참고자료

Abstract : https://limkydev.tistory.com/188
Object : https://docs.oracle.com/javase/tutorial/java/IandI/objectclass.html
Override : https://velog.io/@polynomeer/JAVA%EC%9D%98-%EC%98%A4%EB%B2%84%EB%9D%BC%EC%9D%B4%EB%94%A9Override
super : http://www.tcpschool.com/java/java_inheritance_super
final : https://coding-factory.tistory.com/525
method dispatch : https://defacto-standard.tistory.com/413

0개의 댓글