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
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.
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
15:30 $ javap-c outerclass Compiled from ' Outerclass.java ' public class Outerclass extends java.lang.object{public oute
Rclass (); 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
15:37 $ javap-c outerclass\ $InnerClass Compiled from ' Outerclass.java ' public class Outerclass$innerclass extends JAVA.L Ang.
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.
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.
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.
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.
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 = ten;
}
}
Like the above, use JAVAP to reverse-compile and look. But this time we'll take a look at the results of Innerclass.
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
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
16:08 $ javap-c anotherouterclass Compiled from ' Anotherouterclass.java ' public class Anotherouterclass extends Java.lan
g.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
33:invokestatic #39; Method anotherouterclass$innerclass.access$0: (Lanotherouterclass$innerclass;) I
One more summary.
One of the official Java documents has this sentence
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.
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 + +.
A book that delves into Java details
Java Programming Ideas
Sun Company Core Technology series: effective Java Chinese version
Deep understanding of Java Virtual machines: JVM advanced features and best practices
The above is the Java private modifier data collation, follow-up continue to supplement the relevant information, thank you for your support of this site!