Java java지도 시간 Java의 정적 디스패치 및 동적 디스패치 소개(코드 예)

Java의 정적 디스패치 및 동적 디스패치 소개(코드 예)

Feb 19, 2019 pm 03:56 PM
java

이 기사에서는 Java의 정적 디스패치 및 동적 디스패치에 대해 소개합니다(코드 예제). 도움이 필요한 친구들이 참고할 수 있기를 바랍니다.

최근 JVM에 대한 지식을 복습하면서 정적 디스패치와 동적 디스패치에 대한 이해가 다소 혼란스러워서 직접 코드를 작성하고 지식을 분석에 통합해 보았습니다.

다음 코드가 있습니다. 각 코드는 무엇을 출력하나요?

package com.khlin.my.test;

class Base {

    public static void foo() {
        System.out.println("Base.foo() invoked");
    }

    public void bar(int c) {
        System.out.println("Base.bar(int) invoked");
    }

    public void bar(Character c) {
        System.out.println("Base.bar(Character) invoked");
    }

    public void baz(Object o) {
        System.out.println("Base.baz(Object) invoked");
    }

    public void baz(Integer i) {
        System.out.println("Base.baz(Integer) invoked");
    }

}

class Child extends Base {
    public static void foo() {
        System.out.println("Child.foo() invoked");
    }

    public void bar(Character c) {
        System.out.println("Child.bar(Character) invoked");
    }

    public void bar(char c) {
        System.out.println("Child.bar(char) invoked");
    }
}

public class App {

    public static void main(String[] args) {
        Base child = new Child();

        System.out.println("第1段输出:");
        child.foo();
        child.bar(new Character('C'));

        System.out.println("第2段输出:");
        Object integer = new Integer(100);
        child.baz(integer);

        System.out.println("第3段输出:");
        child.bar('C');

    }
}
로그인 후 복사

코드 컴파일부터 메소드 호출까지 전체 과정을 간략하게 소개하겠습니다.

· Compile

먼저 첫 번째 단락의 출력을 살펴보세요. child.foo()가 상위 클래스 또는 하위 클래스의 정적 메소드를 호출하고 있습니까?

컴파일 단계에서 정적 디스패치가 발생합니다.

1 Base child = new Child();
로그인 후 복사

객체를 생성할 때 위 그림과 같이 Base를 변수의 정적 유형(Static Type) 또는 겉보기 유형(Apparent Type)이라고 하며, 다음 Child를 변수의 실제 유형( 실제 유형).

메서드 실행 버전을 찾기 위해 정적 유형을 사용하는 모든 디스패치 작업을 정적 디스패치라고 합니다. 정적 디스패치의 일반적인 응용 프로그램은 컴파일 단계에서 발생하는 메서드 오버로딩이므로 정적으로 디스패치되도록 결정된 작업이 실제로 가상 머신에서 실행되지 않습니다.

메서드의 수신자(Reciever)와 메소드의 매개변수를 총칭하여 메소드의 변수라고 합니다. 디스패치는 몇 가지 유형의 변수를 기반으로 하느냐에 따라 단일 디스패치와 다중 디스패치로 나눌 수 있습니다.

정적 디스패치 중에 대상 메소드를 선택하는 기준은 두 가지입니다. 하나는 정적 유형이 Base인지 Child인지이고, 다른 하나는 메소드의 매개변수 유형입니다. 따라서 정적 디스패치는 다중 디스패치입니다.

다음으로 “첫 번째 문단 출력” 코드에서 생성된 명령어를 살펴보겠습니다. javap -v App.class 명령어를 통해 얻은 결과는 위의 분석과 일치하는 18행과 31행에서 두 명령어의 기호 참조를 볼 수 있습니다. 자식의 정적 유형은 Base이므로 메서드는 None을 통해 Base 클래스가 선택됩니다. 매개변수 및 문자 유형에 따라 각각 메소드 버전이 결정됩니다.

그러나 결국 둘의 동작은 다릅니다. child.foo()는 정적 유형인 Base의 foo()를 호출하는 반면, child.bar(new Character('C'))는 실제 유형인 Child를 호출합니다. 방법.

이유는 두 명령어가 다르기 때문입니다: Invokestatic과 Invokevirtual

Java 가상 머신은 5가지 메소드 호출 바이트코드 명령어를 제공합니다:

invokestatic: 정적 메소드 호출

invokespecial: 인스턴스 생성자 호출< 메서드 및 상위 클래스 메서드

invokevirtual: 모든 가상 메서드 호출

invokeinterface: 인터페이스 메서드를 호출한 다음 런타임에 이 인터페이스를 구현하는 객체를 결정합니다.

invokedynamic: 먼저 런타임에 이를 동적으로 해결합니다. 콜 포인트에서 참조하는 메서드 그런 다음 이전 4개 호출 명령어의 디스패치 로직이 JVM(Java Virtual Machine) 내에서 구체화되고, Invokedynamic은 사용자가 설정한 부팅 방법에 따라 결정됩니다.

구체적인 이유는 다음 단계(클래스 로딩 구문 분석)에서 다양한 명령어가 다르게 동작하기 때문입니다. 지금은 잠시 제쳐두고 두 번째 단락의 명령어 출력을 살펴보겠습니다.

정적 디스패치 중에는 메소드에 전달된 매개변수의 정적 유형에 따라 호출할 메소드 버전이 결정되는 것을 볼 수 있습니다. baz(Integer) 메소드가 있지만, 들어오는 매개변수 정수 정적 유형은 Object이므로 baz(Object)가 호출됩니다. 세 번째 단락의 지침 출력을 살펴보겠습니다. 기호 참조는 여전히 Base 클래스의 메서드여야 하지만(Child 클래스에 동일한 매개변수를 가진 bar(char c) 메서드가 있음에도 불구하고) Base 메소드에 동일한 매개변수(char 유형)가 없으면 오류가 보고되지 않나요? 어떤 메소드가 호출될까요?

컴파일러가 메서드의 오버로드된 버전을 결정할 수 있지만 많은 경우 이 오버로드된 버전은 "유일한" 버전이 아니며 "더 적절한" 버전만 결정할 수 있는 경우가 많습니다.

· 클래스 로딩 구문 분석 구문 분석 단계는 가상 머신이 상수 풀의 기호 참조를 직접 참조로 바꾸는 프로세스입니다.

invokestatic 및 Invokespecial 명령어로 메서드를 호출할 수 있는 한, 고유한 호출 버전은 구문 분석 단계에서 결정될 수 있습니다. 이 조건을 충족하는 네 가지 범주는 정적 메서드, 개인 메서드, 인스턴스 생성자 및 상위 클래스 메서드입니다. . 기호 참조는 클래스에 로드되어 메서드에 대한 직접 참조로 확인됩니다. 이러한 메서드는 비가상 메서드라고 할 수 있으며, 다른 메서드는 비가상 메서드라고 합니다(최종 메서드 제외).

invokevirtual 명령어를 사용하여 최종 수정된 메서드를 호출하지만 재정의할 수 없고 다른 버전이 없기 때문에 이 메서드도 비가상 메서드입니다.

출력의 첫 번째 단락으로 돌아가서 child.foo()는 호출 정적 명령이므로 구문 분석 단계에서 직접 참조로 대체되고 특정 클래스가 결정되므로 정적 유형 Base.foo() 호출됩니다.

그리고 child.bar(new Character('C'))는 Invokevirtual입니다. 이 단계에서는 호출된 메서드의 서명을 확인할 수 있지만 메서드 수신자의 실제 유형은 아직 확인할 수 없습니다. 동적 디스패치에 의해 결정됩니다. 클러스터 효과가 하나만 있기 때문에 동적 디스패치는 단일 디스패치입니다.

메서드 수신자의 실제 유형은 다음 단계에서 결정됩니다.

· 런타임 시 메소드 호출

런타임 시 실제 유형을 기반으로 메소드 실행 버전을 결정하는 디스패치 프로세스를 동적 디스패치라고 합니다.

최종 출력은 다음과 같습니다.

위 내용은 Java의 정적 디스패치 및 동적 디스패치 소개(코드 예)의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.

핫 AI 도구

Undresser.AI Undress

Undresser.AI Undress

사실적인 누드 사진을 만들기 위한 AI 기반 앱

AI Clothes Remover

AI Clothes Remover

사진에서 옷을 제거하는 온라인 AI 도구입니다.

Undress AI Tool

Undress AI Tool

무료로 이미지를 벗다

Clothoff.io

Clothoff.io

AI 옷 제거제

AI Hentai Generator

AI Hentai Generator

AI Hentai를 무료로 생성하십시오.

인기 기사

R.E.P.O. 에너지 결정과 그들이하는 일 (노란색 크리스탈)
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 최고의 그래픽 설정
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
R.E.P.O. 아무도들을 수없는 경우 오디오를 수정하는 방법
3 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌
WWE 2K25 : Myrise에서 모든 것을 잠금 해제하는 방법
4 몇 주 전 By 尊渡假赌尊渡假赌尊渡假赌

뜨거운 도구

메모장++7.3.1

메모장++7.3.1

사용하기 쉬운 무료 코드 편집기

SublimeText3 중국어 버전

SublimeText3 중국어 버전

중국어 버전, 사용하기 매우 쉽습니다.

스튜디오 13.0.1 보내기

스튜디오 13.0.1 보내기

강력한 PHP 통합 개발 환경

드림위버 CS6

드림위버 CS6

시각적 웹 개발 도구

SublimeText3 Mac 버전

SublimeText3 Mac 버전

신 수준의 코드 편집 소프트웨어(SublimeText3)

자바의 제곱근 자바의 제곱근 Aug 30, 2024 pm 04:26 PM

자바의 제곱근 안내 여기서는 예제와 코드 구현을 통해 Java에서 Square Root가 어떻게 작동하는지 설명합니다.

자바의 완전수 자바의 완전수 Aug 30, 2024 pm 04:28 PM

Java의 완전수 가이드. 여기서는 정의, Java에서 완전 숫자를 확인하는 방법, 코드 구현 예제에 대해 논의합니다.

Java의 난수 생성기 Java의 난수 생성기 Aug 30, 2024 pm 04:27 PM

Java의 난수 생성기 안내. 여기서는 예제를 통해 Java의 함수와 예제를 통해 두 가지 다른 생성기에 대해 설명합니다.

자바의 웨카 자바의 웨카 Aug 30, 2024 pm 04:28 PM

Java의 Weka 가이드. 여기에서는 소개, weka java 사용 방법, 플랫폼 유형 및 장점을 예제와 함께 설명합니다.

Java의 스미스 번호 Java의 스미스 번호 Aug 30, 2024 pm 04:28 PM

Java의 Smith Number 가이드. 여기서는 정의, Java에서 스미스 번호를 확인하는 방법에 대해 논의합니다. 코드 구현의 예.

Java Spring 인터뷰 질문 Java Spring 인터뷰 질문 Aug 30, 2024 pm 04:29 PM

이 기사에서는 가장 많이 묻는 Java Spring 면접 질문과 자세한 답변을 보관했습니다. 그래야 면접에 합격할 수 있습니다.

Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Java 8 Stream foreach에서 나누거나 돌아 오시겠습니까? Feb 07, 2025 pm 12:09 PM

Java 8은 스트림 API를 소개하여 데이터 컬렉션을 처리하는 강력하고 표현적인 방법을 제공합니다. 그러나 스트림을 사용할 때 일반적인 질문은 다음과 같은 것입니다. 기존 루프는 조기 중단 또는 반환을 허용하지만 스트림의 Foreach 메소드는이 방법을 직접 지원하지 않습니다. 이 기사는 이유를 설명하고 스트림 처리 시스템에서 조기 종료를 구현하기위한 대체 방법을 탐색합니다. 추가 읽기 : Java Stream API 개선 스트림 foreach를 이해하십시오 Foreach 메소드는 스트림의 각 요소에서 하나의 작업을 수행하는 터미널 작동입니다. 디자인 의도입니다

Java의 날짜까지의 타임스탬프 Java의 날짜까지의 타임스탬프 Aug 30, 2024 pm 04:28 PM

Java의 TimeStamp to Date 안내. 여기서는 소개와 예제와 함께 Java에서 타임스탬프를 날짜로 변환하는 방법에 대해서도 설명합니다.

See all articles