이 기사에서는 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 중국어 웹사이트의 기타 관련 기사를 참조하세요!

클래스 로더는 통합 클래스 파일 형식, 동적로드, 부모 위임 모델 및 플랫폼 독립적 인 바이트 코드를 통해 다른 플랫폼에서 Java 프로그램의 일관성과 호환성을 보장하고 플랫폼 독립성을 달성합니다.

Java 컴파일러가 생성 한 코드는 플랫폼 독립적이지만 궁극적으로 실행되는 코드는 플랫폼 별입니다. 1. Java 소스 코드는 플랫폼 독립적 인 바이트 코드로 컴파일됩니다. 2. JVM은 바이트 코드를 특정 플랫폼의 기계 코드로 변환하여 크로스 플랫폼 작동을 보장하지만 성능이 다를 수 있습니다.

멀티 스레딩은 프로그램 대응 성과 리소스 활용을 향상시키고 복잡한 동시 작업을 처리 할 수 있기 때문에 현대 프로그래밍에서 중요합니다. JVM은 스레드 매핑, 스케줄링 메커니즘 및 동기화 잠금 메커니즘을 통해 다양한 운영 체제에서 멀티 스레드의 일관성과 효율성을 보장합니다.

Java의 플랫폼 독립성은 작성된 코드가 수정없이 JVM이 설치된 모든 플랫폼에서 실행될 수 있음을 의미합니다. 1) Java 소스 코드는 바이트 코드로 컴파일됩니다. 2) 바이트 코드는 JVM에 의해 해석되고 실행됩니다.

javaapplicationscanindeedencounterplatform-specificissuesdespitetejvm'sabstraction.ressistinclude : 1) nativecodeandlibraries, 2) OperatingSystemDifferences, 3) jvmimplementationvariations, 및 4) 어려운 의존성, 개발자, 1)

클라우드 컴퓨팅은 Java의 플랫폼 독립성을 크게 향상시킵니다. 1) Java Code는 바이트 코드로 컴파일되어 다른 운영 체제에서 JVM에 의해 실행되어 크로스 플랫폼 작동을 보장합니다. 2) Docker 및 Kubernetes를 사용하여 Java 응용 프로그램을 배포하여 휴대 성 및 확장 성을 향상시킵니다.

Java'SplatformIndencealLowsDeveloperstowStowRiteCodeOntOnitOniNanyDeviceOroswithajvm. ThisIsachieAdthroughCompilingTobyTecode, thejvMIngretSorcompileStruntime.thistureatureDificallyNatlyBoostedjava'SADOPTIONDUOCROSS-PLAT-PLAT-PLAT-PLAT-PLAT-PLAT-PLAT-PLAT-PPLATION

Docker와 같은 컨테이너화 기술은 Java의 플랫폼 독립성을 대체하기보다는 향상됩니다. 1) 환경 간 일관성을 보장, 2) 특정 JVM 버전을 포함한 종속성 관리, 3) 배포 프로세스를 단순화하여 Java 응용 프로그램을보다 적응 가능하고 관리 할 수 있도록합니다.


핫 AI 도구

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

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

Undress AI Tool
무료로 이미지를 벗다

Clothoff.io
AI 옷 제거제

Video Face Swap
완전히 무료인 AI 얼굴 교환 도구를 사용하여 모든 비디오의 얼굴을 쉽게 바꾸세요!

인기 기사

뜨거운 도구

ZendStudio 13.5.1 맥
강력한 PHP 통합 개발 환경

Eclipse용 SAP NetWeaver 서버 어댑터
Eclipse를 SAP NetWeaver 애플리케이션 서버와 통합합니다.

DVWA
DVWA(Damn Vulnerable Web App)는 매우 취약한 PHP/MySQL 웹 애플리케이션입니다. 주요 목표는 보안 전문가가 법적 환경에서 자신의 기술과 도구를 테스트하고, 웹 개발자가 웹 응용 프로그램 보안 프로세스를 더 잘 이해할 수 있도록 돕고, 교사/학생이 교실 환경 웹 응용 프로그램에서 가르치고 배울 수 있도록 돕는 것입니다. 보안. DVWA의 목표는 다양한 난이도의 간단하고 간단한 인터페이스를 통해 가장 일반적인 웹 취약점 중 일부를 연습하는 것입니다. 이 소프트웨어는

VSCode Windows 64비트 다운로드
Microsoft에서 출시한 강력한 무료 IDE 편집기

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