Java의 최종 키워드는 일반적으로 Try Catch Block과 함께 사용됩니다. 방법이 끝나기 전에 또는 예외가 발생할 때 일부 리소스 릴리스 작업을 수행하는 데 사용됩니다. 최근 인터넷에서 Try Catch의 실행 순서에 대해 논의하는 몇 가지 기사를 보았으며, 마지막으로 블록이 방법의 끝에서 실행되도록해야합니다.
이러한 견해는 일반적으로 다음을 믿습니다.
1) 프로그램 리턴 명령문 이후 이전 메소드로 돌아 가기 전에 최종 키워드가 실행됩니다. 반환 값은 임시 영역에 저장됩니다. 최종 블록이 실행되면 임시 영역의 값이 반환됩니다.
2) 최종 블록에 반환 값이있는 경우 프로그램의 이전 시도 또는 캐치 블록의 임시 영역에 저장된 값을 대체합니다.
그러나 문제가 정말로 이렇게? 주의 깊게 생각합시다. JVM은 런타임에 바이트 코드 지침을 설명하고 실행합니다. Return 문을 실행할 때, 그는 마지막으로 블록이 있는지 알지 못합니다. 마지막으로 블록이 없다면 어떻게해야합니까? 바이트 코드 명령어 여부에 관계없이 컴퓨터 명령이 명확해야합니다. JVM은 그다지 똑똑하지 않습니다. 동일한 지시가 명확해야하며 두 가지 의미를 포함하지 않습니다. 따라서, 실행시 반환 명령문에 관계없이 스택의 내용이 팝업되어 호출 방법으로 돌아갑니다.
동시에, 우리는 "Java Virtual Machine에 깊이"라는 책이 또 다른 설명을한다는 것을 알 수 있습니다. Java 컴파일러가 최종 조항을 컴파일하면 JSR 명령이 생성됩니다. 그것은 JVM을 실행을 위해 미니 서브 루틴으로 호출하게됩니다. 즉, 마침내 블록에서. 동시에, 프로그램의 반환 0 명령문은 JSR 명령을 호출하기 전에 스택의 리턴 변수로 컴파일되며 JSR 명령을 호출하고 최종 블록이 실행되고 최종 블록 리턴이 표시됩니다. 로컬 변수의 반환 값이 스택으로 밀려 나면 Ireturn 명령이 실행되고 리턴 값이 스택에서 팝업되어 통화 메소드로 돌아갑니다. 여기서, 마지막 블록을 실행하는 동안 예외가 발생하거나 반환 값도 있기 때문에 JSR 명령을 실행하기 전에 로컬 변수에 반환 값이 저장됩니다. 이런 식으로 만 최종 프로그램 실행의 일관성을 보장 할 수 있습니다. "심화 Java Virtual Machine"은 얼마 동안 작성되었으므로 저자가 사용하는 JVM 컴파일러의 구현 및 버전 도이 기사에서 논의 된 것과 다릅니다. 따라서 테스트 후 다른 컴파일러 구현에 대한 바이트 코드 생성 또는 동일한 프로그램에 대한 다른 컴파일러 버전에 약간의 차이가 있습니다. 관심이 있으시면이 책의 최종 조항에 의해 생성 된 바이트 코드를 살펴볼 수 있습니다.
이 기사의 바이트 코드 생성은 Oracle의 JDK8U-25 버전의 컴파일러에 의해 컴파일되고 생성됩니다.
아래 예를 살펴 보겠습니다.
1. 마리 캐치 드디어 예제 :
공개 클래스 마침내 테스트 {public static void main (String [] args) {int r = test (); System.out.println (R); } public static int test () {try {system.out.println ( "try"); // 반환 1/0; 반환 0; } catch (예외 e) {System.out.println ( "예외"); 반환 100; } 마침내 {system.out.println ( "최종"); }}}시도 블록에서 반환 0 명령문을 사용하면 프로그램의 실행 결과는 다음과 같습니다.
노력하다
마지막으로
0
시도 블록에서 반환 1/0 문을 사용하면 프로그램 실행 결과는 다음과 같습니다.
예외
마지막으로
100
실제로, 실행 결과를 통해, 우리는 시도 또는 캐치 블록의 리턴 명령문 전에 다른 명세서 후에 마지막으로 블록이 실행된다는 것을 알 수 있습니다. 다시 말해, JVM이 Bytecode를 해석하고 실행하기 때문에 프로그램의 쓰기 순서는 실행 순서와 일치하지 않으므로 Java 컴파일러 가이 코드를 컴파일하는 방법을 확인하고 바이트 코드에서 생성 한 내용을 확인해야합니다.
2. 프로그램에 의해 생성 된 바이트 코드의 일부 : (Java Bytecode 명령어를 참조하십시오)
공개 정적 int test (); 디스크립터 : () I 플래그 : Acc_Public, Acc_static 코드 : stack = 2, locals = 2, args_size = 0 0 : getstatic #20 // Field Java/lang/System.out : ljava/io/printstream; 3 : LDC #36 // String try 5 : invokeVirtual #38 // 메소드 java/io/printstream.println : (ljava/lang/string;) v 8 : getstatic #20 // Field Java/Lang/System.out : ljava/io/pintstream; 11 : LDC #41 // string 마침내 13 : invokeVirtual #38 // 메소드 Java/IO/PrintStream.println : (ljava/lang/string;) v 16 : Ireturn 18 : Ireturn 18 : Store_0 19 : Getstatic #20 // Field Java/Lang/System.out : Ljava/PrintsteM; 22 : LDC #43 // String Exception 24 : InvokeVirtual #38 // 메소드 Java/IO/PrintStream.println : (ljava/lang/string;) v 27 : getstatic #20 // Field Java/Lang/System.out : ljava/io/printstream; 30 : LDC #41 // string 최종 32 : invokeVirtual #38 // 메소드 Java/IO/PrintStream.println : (ljava/lang/string;) v 35 : Bipush 100 37 : Ireturn 38 : Store_1 39 : getstatic #20 // Field Java/Lang/System.out : ljava/printestream; 42 : LDC #41 // String 마침내 44 : InvokeVirtual #38 // 메소드 Java/IO/Printstream.println : (ljava/lang/string;) v 47 : Aload_1 48 : Athrow Excepcesion 테이블 : 0에서 to top java/lang/예외 0 27 38
빨간색 부분에서, 10 번과 11 행은 마지막으로 블록 명령문 지침에 해당한다는 것을 알 수 있습니다. 16과 17은 반환 전에 시도 블록에 대한 다른 명령문 후에 반환 0 명령어에 해당한다는 것을 알 수 있습니다. 19와 20은 마지막으로 블록 지침에 해당하며, 21과 22는 리턴 100 문의 지침에 해당합니다. 다른 진술을 포착하고 돌아 오기 전에, 우리는이 뒤에 모든 일이 일어나는 것이 Java 컴파일러가 우리를 위해이 모든 일을했다는 것을 알 수 있습니다. 프로그램에서 발생하는 예외는 JVM에서 예외 테이블에서 예외를 처리하기 위해 해당 주소 위치를 찾을 수 있습니다.
따라서 최종 블록의 명령문은 Try Block 및 Catch Block Return 문 앞에와 다른 문장 후에 Java 컴파일러에 의해 삽입 될 것이라고 결론을 내릴 수 있습니다. 여기서 JSR 전화를 생성 할 서브 루틴은 없습니다. 그렇기 때문에 시도 블록을 실행하든 캐치 블록을 실행하든 메소드가 반환되기 전에 최종 블록이 실행됩니다.
Java의 실행 타이밍에 대한 위의 포괄적 인 분석은 마지막으로 내가 공유하는 모든 컨텐츠입니다. 나는 당신이 당신에게 참조를 줄 수 있기를 바랍니다. 그리고 당신이 wulin.com을 더 지원할 수 있기를 바랍니다.