我很好奇JVM是如何工作的. JVM是否确认方法可访问性规则,如“private”受保护或仅在编译时完成?
例如,是否可以在第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,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,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; } */
解决方法
To the JLS!
15.12.4 Runtime Evaluation of Method Invocation
At run time,method invocation requires five steps. First,a target reference may be computed. Second,the argument expressions are evaluated. Third,the accessibility of the method to be invoked is checked. Fourth,the actual code for the method to be executed is located. Fifth,a new activation frame is created,synchronization is performed if necessary,and control is transferred to the method code.
JLS的措辞表明将在运行时检查可访问性.