In Java programming, a member is decorated with the private keyword, and only the class in which the member is located and the method of the class are available, and no other class can access the private member.
The basic function of the private modifier is described above, and today we will look at the failure of private functions.
Java Inner class
In Java, it is believed that many people have used the inner class, Java allows the definition of another class within a class, the class inside the class is the inner class, also known as nested classes. A simple inner-class implementation can be as follows
Copy Code code as follows:
Class Outerclass {
Class innerclass{
}
}
Today's problem is related to the Java internal class, and only involves some of the internal class knowledge related to the study of this article, specifically on the Java internal class follow-up articles will be introduced.
The first time you fail?
A scenario that we often use in programming is to access the private member variables or methods of an external class inside an internal class, which is OK. such as the following code implementation.
Copy Code code as follows:
public class Outerclass {
Private String language = "en";
Private String region = "US";
public class Innerclass {
public void Printouterclassprivatefields () {
String fields = "language=" + language + "; region=" + region;
System.out.println (fields);
}
}
public static void Main (string[] args) {
Outerclass outer = new Outerclass ();
Outerclass.innerclass inner = outer.new innerclass ();
Inner.printouterclassprivatefields ();
}
}
What is this, not a private-decorated member that can only be accessed by a class described by a member? Is private really ineffective?
The compiler is in mischief?
We use the JAVAP command to view the generated two class files
Outerclass Results of the reverse compilation
Copy Code code as follows:
15:30 $ javap-c Outerclass
Compiled from "Outerclass.java"
public class Outerclass extends java.lang.object{
public Outerclass ();
Code:
0:aload_0
1:invokespecial #11; Method Java/lang/object. " <init> ":() V
4:aload_0
5:LDC #13; String en
7:putfield #15; Field language:ljava/lang/string;
10:aload_0
11:LDC #17; String US
13:putfield #19; Field region:ljava/lang/string;
16:return
public static void Main (java.lang.string[]);
Code:
0: new #1;//class outerclass
3: DUP
; 4: invokespecial #27; Method "<init>":() V
7: astore_1
8: new #28//class Outerclass$innerclass
11:dup
12:aload_1
13:dup
14: invokevirtual #30; Method Java/lang/object.getclass: () Ljava/lang/class;
17:pop
18:invokespecial #34;//method outerclass$innerclass. " <init>:(Louterclass) V
21:astore_2
22:aload_2
23: invokevirtual #37; Method Outerclass$innerclass.printouterclassprivatefields: () V
26:return
Static java.lang.String access$0 (Outerclass);
Code:
0:aload_0
1:getfield #15; Field language:ljava/lang/string;
4:areturn
Static java.lang.String access$1 (Outerclass);
Code:
0:aload_0
1:getfield #19; Field region:ljava/lang/string;
4:areturn
}
Hey? No, we didn't define these two methods in the Outerclass.
Static java.lang.String access$0 (Outerclass);
Code:
0:aload_0
1:getfield #15; Field language:ljava/lang/string;
4:areturn
Static java.lang.String access$1 (Outerclass);
Code:
0:aload_0
1:getfield #19; Field region:ljava/lang/string;
4:areturn
}
From the comment given, ACCESS$0 returns the Language property of Outerclass, Access$1 returns Outerclass property of region. And both of these methods accept instances of Outerclass as arguments. Why are these two methods generated and what is the effect? Let's take a look at the decompile results of the inner class.
Outerclass$innerclass Results of the reverse compilation
Copy Code code as follows:
15:37 $ javap-c outerclass\ $InnerClass
Compiled from "Outerclass.java"
public class Outerclass$innerclass extends java.lang.object{
Final Outerclass this$0;
Public Outerclass$innerclass (Outerclass);
Code:
0:aload_0
1:aload_1
2:putfield #10; Field This$0:louterclass;
5:aload_0
6:invokespecial #12; Method Java/lang/object. " <init> ":() V
9:return
public void Printouterclassprivatefields ();
Code:
0:new #20; Class Java/lang/stringbuilder
3:dup
4:LDC #22; String language=
6:invokespecial #24; Method Java/lang/stringbuilder. " <init> ":(ljava/lang/string;) V
9:aload_0
10:getfield #10; Field This$0:louterclass;
13:invokestatic #27; Method outerclass.access$0: (Louterclass;) ljava/lang/string;
16:invokevirtual #33; Method Java/lang/stringbuilder.append: (ljava/lang/string;) Ljava/lang/stringbuilder;
19:LDC #37; String; region=
21:invokevirtual #33; Method Java/lang/stringbuilder.append: (ljava/lang/string;) Ljava/lang/stringbuilder;
24:aload_0
25:getfield #10; Field This$0:louterclass;
28:invokestatic #39; Method outerclass.access$1: (Louterclass;) ljava/lang/string;
31:invokevirtual #33; Method Java/lang/stringbuilder.append: (ljava/lang/string;) Ljava/lang/stringbuilder;
34:invokevirtual #42; Method java/lang/stringbuilder.tostring: () ljava/lang/string;
37:astore_1
38:getstatic #46; Field Java/lang/system.out:ljava/io/printstream;
41:aload_1
42:invokevirtual #52; Method Java/io/printstream.println: (ljava/lang/string;) V
45:return
}
The following code calls ACCESS$0 's code to get Outerclass's language private property.
Copy Code code as follows:
13:invokestatic #27; Method outerclass.access$0: (Louterclass;) ljava/lang/string;
The following code calls the ACCESS$1 code to get the region private property of the Outherclass.
Copy Code code as follows:
28:invokestatic #39; Method outerclass.access$1: (Louterclass;) ljava/lang/string;
Note: When an inner class is constructed, a reference to the outer class is passed in and as an attribute of the inner class, so the inner class holds a reference to its outer class.
This$0 is an external class reference held by the inner class that passes the reference and assigns a value by constructing the method.
Copy Code code as follows:
Final Outerclass this$0;
Public Outerclass$innerclass (Outerclass);
Code:
0:aload_0
1:aload_1
2:putfield #10; Field This$0:louterclass;
5:aload_0
6:invokespecial #12; Method Java/lang/object. " <init> ":() V
9:return
Summary
This part of private appears to be invalidated and is not actually invalidated, because when the inner class calls the private property of the external class, its true execution is to get the property values by invoking the static method of the compiler-generated property (i.e. acess$0,access$1, etc.). All of this is the compiler's special treatment.
This time, too?
If the above writing is very common, then the writing is not very little contact, but it can be run.
Copy Code code as follows:
public class Anotherouterclass {
public static void Main (string[] args) {
Innerclass inner = new Anotherouterclass (). New Innerclass ();
System.out.println ("Innerclass Filed =" + inner.x);
}
Class Innerclass {
private int x = 10;
}
}
Like the above, use JAVAP to reverse-compile and look. But this time we'll take a look at the results of Innerclass.
Copy Code code as follows:
16:03 $ javap-c anotherouterclass\ $InnerClass
Compiled from "Anotherouterclass.java"
Class Anotherouterclass$innerclass extends java.lang.object{
Final Anotherouterclass this$0;
Anotherouterclass$innerclass (Anotherouterclass);
Code:
0:aload_0
1:aload_1
2:putfield #12; Field This$0:lanotherouterclass;
5:aload_0
6:invokespecial #14; Method Java/lang/object. " <init> ":() V
9:aload_0
10:bipush 10
12:putfield #17; Field x:i
15:return
static int access$0 (ANOTHEROUTERCLASS$INNERCLASS);
Code:
0:aload_0
1:getfield #17; Field x:i
4:ireturn
}
Again, the compiler automatically generates a backdoor method that gets the private property access$0 one time to get the value of X.
Anotherouterclass.class Results of the reverse compilation
Copy Code code as follows:
16:08 $ javap-c Anotherouterclass
Compiled from "Anotherouterclass.java"
public class Anotherouterclass extends java.lang.object{
public Anotherouterclass ();
Code:
0:aload_0
1:invokespecial #8; Method Java/lang/object. " <init> ":() V
4:return
public static void Main (java.lang.string[]);
Code:
0:new #16; Class Anotherouterclass$innerclass
3:dup
4:new #1; Class Anotherouterclass
7:dup
8:invokespecial #18; Method "<init>":() V
11:dup
12:invokevirtual #19; Method Java/lang/object.getclass: () Ljava/lang/class;
15:pop
16:invokespecial #23; Method Anotherouterclass$innerclass. " <init> ":(lanotherouterclass;) V
19:astore_1
20:getstatic #26; Field Java/lang/system.out:ljava/io/printstream;
23:new #32; Class Java/lang/stringbuilder
26:dup
27:LDC #34; String Innerclass Filed =
29:invokespecial #36; Method Java/lang/stringbuilder. " <init> ":(ljava/lang/string;) V
32:aload_1
33:invokestatic #39; Method anotherouterclass$innerclass.access$0: (Lanotherouterclass$innerclass;) I
36:invokevirtual #43; Method Java/lang/stringbuilder.append: (I) Ljava/lang/stringbuilder;
39:invokevirtual #47; Method java/lang/stringbuilder.tostring: () ljava/lang/string;
42:invokevirtual #51; Method Java/io/printstream.println: (ljava/lang/string;) V
45:return
}
Where this invocation is the action of the outer class to get the private property x through an instance of the inner class
Copy Code code as follows:
33:invokestatic #39; Method anotherouterclass$innerclass.access$0: (Lanotherouterclass$innerclass;) I
one more summary.
One of the official Java documents has this sentence
Copy Code code as follows:
If the or constructor is declared private, then access are permitted if and only if it occurs within the body of the The top level Class (§7.6) is that encloses the declaration's member or constructor.
This means that if members and constructors (inner classes) are set to private modifiers, they are allowed only if they are accessed by the external class.
How to let internal class private members not be accessed externally
Believe that after reading the above two parts, you will feel that the internal class of private members want to not be outside the class access is very difficult, who let the compiler "nosy", in fact, can be done. That is using anonymous inner classes.
Mrunnable.x is not allowed because the type of the Mrunnable object is runnable rather than the type of the anonymous inner class (we cannot get it properly), and the runanble has no x attribute in it.
Copy Code code as follows:
public class Privatetoouter {
Runnable mrunnable = new Runnable () {
private int x=10;
@Override
public void Run () {
SYSTEM.OUT.PRINTLN (x);
}
};
public static void Main (string[] args) {
Privatetoouter p = new Privatetoouter ();
SYSTEM.OUT.PRINTLN ("Anonymous class private filed=" + p.mrunnable.x); Not allowed
P.mrunnable.run (); Allowed
}
}
Final summary
In this article, the private surface appears to be invalid, but in fact it is not, but in the use of indirect methods to get private properties.
Java's internal class construction holds the application of external classes, C + + does not, this is not the same as C + +.