프로그램이 실행 중일 때 메서드 호출이 가장 일반적이고 자주 발생하는 작업입니다.
메서드 호출은 메서드 실행과 동일하지 않습니다.
메서드 호출 단계의 유일한 작업은 메서드를 결정하는 것입니다. 즉, 어떤 메소드가 호출되는지, 메소드 내부의 특정 실행 프로세스가 포함되지 않습니다. 클래스 파일의 컴파일 프로세스에는 클래스 파일의 모든 메소드 호출이 저장되지 않습니다. 클래스 파일에서는 모두 실제 런타임 메모리 레이아웃의 메서드 항목 주소가 아닌 기호 참조입니다. 즉, 이전 직접 참조입니다.
Java 메서드도 만듭니다. 호출 프로세스가 상대적으로 복잡해집니다.
대상 메서드에 대한 직접 참조는 클래스 로딩 중에 또는 런타임 중에도 결정되어야 합니다.
정적 메서드:
유형과 직접 관련됨개인 메서드:
외부에서 액세스할 수 없음이 두 메소드의 각각의 특징 이 두 메소드 중 어느 것도 상속이나 다른 메소드를 통해 재정의될 수 없으므로 클래스 로딩 단계에서 구문 분석에 적합하다고 결정되었습니다.
Static Methods
Instance Constructors
public class StaticDispatch { static abstract class Human { } static class Man extends Human { } static class Woman extends Human { } public static void sayHello(Human guy) { System.out.println("Hello, Guy!"); } public static void sayHello(Man guy) { System.out.println("Hello, Gentleman!"); } public static void sayHello(woman guy) { System.out.println("Hello, Lady!"); } public static void main(String[] args) { Human man = new Man(); Human women = new Woman(); sayHello(man); sayHello(woman); } }
Human
은 변수의 정적 유형입니다.
Man
은 변수의 실제 유형입니다.
정적 유형과 실제 유형 모두 프로그램에서 변경됩니다:정적 유형:
Human
为变量的静态类型
Man
정적 유형은 사용될 때만 변경됩니다. 변수 자체의 정적 유형은 변경되지 않습니다. 실제 유형은 컴파일러에 알려져 있습니다. :
어서
Human human = new Man(); sayHello(man); sayHello((Man)man); // 类型转换,静态类型变化,转型后的静态类型一定是Man man = new woman(); // 实际类型变化,实际类型是不确定的 sayHello(man); sayHello((Woman)man); // 类型转换,静态类型变化
정적 디스패치:
메서드의 실행 버전을 찾기 위해 정적 유형에 의존하는 모든 디스패치 작업
: 메서드 오버로드
public class LiteralTest { public static void sayHello(char arg) { System.out.println("Hello, char!"); } public static void sayHello(int arg) { System.out.println("Hello, int!"); } public static void sayHello(long arg) { System.out.println("Hello, long!"); } public static void sayHello(Character arg) { System.out.println("Hello, Character!"); } public static void main(String[] arg) { sayHello('a'); } }컴파일러는 오버로드된 메서드에 위에서 아래로 주석을 달아 다른 출력을 얻습니다
컴파일러가 변환을 사용자 정의할 유형을 결정할 수 없는 경우 유형 모호성을 표시하고 컴파일을 거부합니다
public class LiteralTest { public static void sayHello(String arg) { // 新增重载方法 System.out.println("Hello, String!"); } public static void sayHello(char arg) { System.out.println("Hello, char!"); } public static void sayHello(int arg) { System.out.println("Hello, int!"); } public static void sayHello(long arg) { System.out.println("Hello, long!"); } public static void sayHello(Character arg) { System.out.println("Hello, Character!"); } public static void main(String[] args) { Random r = new Random(); String s = "abc"; int i = 0; sayHello(r.nextInt() % 2 != 0 ? s : 1 ); // 编译错误 sayHello(r.nextInt() % 2 != 0 ? 'a' : false); //编译错误 } }동적 디스패치
public class DynamicDispatch { static abstract class Human { protected abstract void sayHello(); } static class Man extends Human { @override protected void sayHello() { System.out.println("Man Say Hello!"); } } static class Woman extends Human { @override protected void sayHello() { System.out.println("Woman Say Hello!"); } } public static void main(String[] args) { Human man = new Man(); Human women = new Woman(); man.sayHello(); woman.sayHello(); man = new Woman(); man.sayHello(); } }
Human두 변수에 따라 결정되지 않습니다. man
andsayHello() 메서드를 호출하고 있습니다.
변수man
이 두 번의 호출에서 서로 다른 메서드를 수행했습니다. 이 현상의 원인: 실제 유형 이 두 변수는 서로 다릅니다
Java virtual 머신이 실제 유형에 따라 메소드의 실행 버전을 전달하는 방법: invokevirtual 명령어의 다형성 검색 프로세스에서 시작하여 Invokevirtual의 런타임 구문 분석 프로세스 명령은 대략 다음 단계로 나뉩니다.
피연산자 스택 찾기로 표시되는 상단의 첫 번째 요소가 가리키는 객체의 실제 유형
상수에 있는 설명자와 간단한 이름이 일치하는 메서드가 유형 C에서 발견되면 액세스 권한 확인이 수행되고 확인에 성공하면 이 메서드에 대한 직접 참조가 반환되고 확인되면 검색 프로세스가 종료됩니다. 실패하면 java.lang.illegalAccessErrorException
발생
아직 찾지 못한 경우 적합한 메소드를 찾으면
실제 유형을 기반으로 메서드 실행 버전을 결정하는 이 디스패치 프로세스 런타임 동안의 작업을 동적 디스패치라고 합니다
가상 머신의 동적 할당 구현
가상 머신의 개념을 분석하는 모드는 정적 할당과 동적 할당으로 "할당 중에 가상 머신이 수행할 작업"에 대한 질문을 이해할 수 있습니다. 가상 머신"은 구체적으로 어떻게 작동합니까? " 다양한 가상 머신 구현에는 차이가 있습니다.
동적 디스패치는 매우 빈번한 작업이고 동적 디스패치의 메서드 버전 선택 프로세스에는 다음 검색이 필요하기 때문입니다. 런타임 시 클래스의 메서드 메타데이터에 있는 적절한 대상 메서드
따라서 가상 머신의 실제 구현에서는 성능상의 이유로 대부분의 구현에서는 실제로 이러한 빈번한 검색을 수행하지 않습니다
Virtual Method Table(vtable)을 생성하여 클래스를 제공하는 것이며,
메타데이터 검색 대신각 메소드의 실제 항목 주소 은 가상 메서드 테이블에 저장됩니다.
하위 클래스에서 메서드가 재정의되지 않은 경우 하위 클래스의 가상 메서드 테이블에 있는 주소 항목은 상위 클래스에 있는 동일한 메서드의 주소 항목과 일치합니다. , 둘 다 상위 클래스의 실제 항목을 가리킵니다
상위 클래스와 하위 클래스에서 동일한 시그니처를 가진 메소드 가상 메소드 테이블의 인덱스 번호는 동일합니다.
메서드 테이블은 일반적으로 클래스 로딩 단계의 연결 단계에서 초기화가 수행됩니다.
변수의 초기 값을 준비한 후 클래스의 가상 머신은 클래스의 메소드 테이블도 초기화합니다위 내용은 Java 메소드 호출을 사용하여 정적 및 동적 디스패치 해결의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!