我很好奇JVM的工作方式。JVM是否承认诸如“专用”之类的方法可访问性规则受保护,还是仅在编译时完成?
例如,是否可以在第37行附近进行一些字节码操作并调用一个受保护的方法,例如test3?通常,编译器不会让我调用该方法,因为它被声明为protected。但是我很好奇,是否在运行时强制执行了该受保护的规则?
u.test1(); //在运行时是否可以通过字节码操作来调用“ test3” // @ line37
package org.berlin.algo.basic.test; public class RunX { private String zzz = "rrrrr"; public void test1() { // Note: I am intentionally use 'new' here as part of my test, not a // good practice I know but allowed by the language. Object x = new String("Test1 -----[1.1] " + zzz); x = new String("Test1 --- [1.2]" + x.toString()); System.out.println(x); this.test2(); this.test3(); } /** * Here, I noticed that the compiler removed my 'test2' code block. * Does that always happen? */ private void test2() { Object x = new String("Test2@line21--->>> [2.1]"); System.out.println(x); } protected void test3() { Object x = new String("Test3@line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1]"); x = new String("Test3@line28--->>> [3.2]"); System.out.println(x); } public static void main(final String [] args) { System.out.println("Running"); RunX u = new RunX(); u.test1(); // Is it possible at runtime, to call 'test3' through bytecode manipulation // @line37 System.out.println("Done"); } } // End of the Class // /* JVM bytecode: javap -v RunX Compiled from "RunX.java" public class org.berlin.algo.basic.test.RunX extends java.lang.Object SourceFile: "RunX.java" minor version: 0 major version: 50 Constant pool: const #1 = class #2; // org/berlin/algo/basic/test/RunX const #2 = Asciz org/berlin/algo/basic/test/RunX; ... ... const #84 = Asciz SourceFile; const #85 = Asciz RunX.java; { public org.berlin.algo.basic.test.RunX(); Code: Stack=2, Locals=1, Args_size=1 0: aload_0 1: invokespecial #10; //Method java/lang/Object."<init>":()V 4: aload_0 5: ldc #12; //String rrrrr 7: putfield #14; //Field zzz:Ljava/lang/String; 10: return LineNumberTable: line 3: 0 line 5: 4 line 3: 10 LocalVariableTable: Start Length Slot Name Signature 0 11 0 this Lorg/berlin/algo/basic/test/RunX; public void test1(); Code: Stack=5, Locals=2, Args_size=1 0: new #21; //class java/lang/String 3: dup 4: new #23; //class java/lang/StringBuilder 7: dup 8: ldc #25; //String Test1 -----[1.1] 10: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 13: aload_0 14: getfield #14; //Field zzz:Ljava/lang/String; 17: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 20: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 23: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V 26: astore_1 27: new #21; //class java/lang/String 30: dup 31: new #23; //class java/lang/StringBuilder 34: dup 35: ldc #39; //String Test1 --- [1.2] 37: invokespecial #27; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V 40: aload_1 41: invokevirtual #41; //Method java/lang/Object.toString:()Ljava/lang/String; 44: invokevirtual #30; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 47: invokevirtual #34; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 50: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V 53: astore_1 54: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream; 57: aload_1 58: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 61: aload_0 62: invokespecial #54; //Method test2:()V 65: aload_0 66: invokevirtual #57; //Method test3:()V 69: return LocalVariableTable: Start Length Slot Name Signature 0 70 0 this Lorg/berlin/algo/basic/test/RunX; 27 43 1 x Ljava/lang/Object; protected void test3(); Code: Stack=3, Locals=2, Args_size=1 0: new #21; //class java/lang/String 3: dup 4: ldc #66; //String Test3@line27 {Will the JVM enforce the 'protected' method rule for test3? --->>> [3.1] 6: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V 9: astore_1 10: new #21; //class java/lang/String 13: dup 14: ldc #68; //String Test3@line28--->>> [3.2] 16: invokespecial #38; //Method java/lang/String."<init>":(Ljava/lang/String;)V 19: astore_1 20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream; 23: aload_1 24: invokevirtual #48; //Method java/io/PrintStream.println:(Ljava/lang/Object;)V 27: return LocalVariableTable: Start Length Slot Name Signature 0 28 0 this Lorg/berlin/algo/basic/test/RunX; 10 18 1 x Ljava/lang/Object; public static void main(java.lang.String[]); Code: Stack=2, Locals=2, Args_size=1 0: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream; 3: ldc #72; //String Running 5: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 8: new #1; //class org/berlin/algo/basic/test/RunX 11: dup 12: invokespecial #76; //Method "<init>":()V 15: astore_1 16: aload_1 17: invokevirtual #77; //Method test1:()V 20: getstatic #42; //Field java/lang/System.out:Ljava/io/PrintStream; 23: ldc #79; //String Done 25: invokevirtual #74; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 28: return LocalVariableTable: Start Length Slot Name Signature 0 29 0 args [Ljava/lang/String; 16 13 1 u Lorg/berlin/algo/basic/test/RunX; } */
到JLS!
15.12.4方法调用的 运行时评估在运行时,方法调用需要五个步骤。首先,可以计算目标参考。其次,对参数表达式进行求值。 第三,检查要调用的方法的可访问性。 第四,找到要执行的方法的实际代码。第五,创建一个新的激活框架,必要时执行同步,并将控制权转移到方法代码。
JLS的措词表示将在运行时检查可访问性。