I was curious about how the JVM works. Does the JVM acknowledge method accesibility rules like 'private' protected or is that only done at compile time?
For example, is it possible at around line37 to do some bytecode manipulation and call a protected method, say test3? Normally the compiler would not let me call that method because it is declared protected. But I was curious if that protected rule is enforced at runtime?
u.test1();
// Is it possible at runtime, to call 'test3' through bytecode manipulation
// @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;
}
*/
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.
The wording of the JLS indicates that the accessibility would be checked at runtime.
The JVM does acknowledge these. They can be overridden, by calling setAccessible(true)
as Prashant Bhate does, but by default they are enforced. (See http://download.oracle.com/javase/6/docs/api/java/lang/reflect/AccessibleObject.html#setAccessible%28boolean%29.)
By the way, you write that "the compiler doesn't encode type method visibility rules into the Java bytecde file"; but it does. In addition to the above, it has to encode these, for a number of reasons. For example:
getModifiers()
method).If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With