Java private修飾符失效的原因
失效之Java內(nèi)部類
在一個(gè)內(nèi)部類里訪問外部類的private成員變量或者方法。
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(); } }
查看原因
使用javap命令查看一下生成的class文件
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 OuterClassInnerClass 11: dup 12: aload_1 13: dup 14: invokevirtual #30; //Method java/lang/Object.getClass:()Ljava/lang/Class; 17: pop 18: invokespecial #34; //Method OuterClassInnerClass."<init>":(LOuterClass;)V 21: astore_2 22: aload_2 23: invokevirtual #37; //Method OuterClassInnerClass.printOuterClassPrivateFields:()V 26: return static java.lang.String access0(OuterClass); Code: 0: aload_0 1: getfield #15; //Field language:Ljava/lang/String; 4: areturn static java.lang.String access1(OuterClass); Code: 0: aload_0 1: getfield #19; //Field region:Ljava/lang/String; 4: areturn }
在這里有一個(gè)OuterClass方法,
static java.lang.String access0(OuterClass); Code: 0: aload_0 1: getfield #15; //Field language:Ljava/lang/String; 4: areturn static java.lang.String access1(OuterClass); Code: 0: aload_0 1: getfield #19; //Field region:Ljava/lang/String; 4: areturn }
根據(jù)注釋,可以知道access0返回outerClass的language屬性,access1返回outerClass的region屬性,并且這兩個(gè)方法都接受OuterClass的實(shí)例作為參數(shù),
對(duì)這兩個(gè)方法進(jìn)行反編譯。
15:37 javap -c OuterClassInnerClass Compiled from "OuterClass.java" public class OuterClassInnerClass extends java.lang.Object{ final OuterClass this0; public OuterClassInnerClass(OuterClass); Code: 0: aload_0 1: aload_1 2: putfield #10; //Field this0: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 this0:LOuterClass; 13: invokestatic #27; //Method OuterClass.access0:(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 this0:LOuterClass; 28: invokestatic #39; //Method OuterClass.access1:(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 }
下面代碼調(diào)用access$0的代碼,其目的是得到OuterClass的language 私有屬性。
13: invokestatic #27; //Method OuterClass.access$0:(LOuterClass;)Ljava/lang/String;
下面代碼調(diào)用了access$1的代碼,其目的是得到OutherClass的region 私有屬性。
28: invokestatic #39; //Method OuterClass.access$1:(LOuterClass;)Ljava/lang/String;
即,在內(nèi)部類構(gòu)造的時(shí)候,會(huì)有外部類的引用傳遞進(jìn)來,并且作為內(nèi)部類的一個(gè)屬性,所以內(nèi)部類會(huì)持有一個(gè)其外部類的應(yīng)用。
this$0就是內(nèi)部類持有的外部類引用,通過構(gòu)造方法傳遞引用并賦值。
final OuterClass this0; public OuterClassInnerClass(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
繼續(xù)失效
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; } }
和上面一樣,使用Javap反編譯一下
16:03 javap -c AnotherOuterClassInnerClass Compiled from "AnotherOuterClass.java" class AnotherOuterClassInnerClass extends java.lang.Object{ final AnotherOuterClass this0; AnotherOuterClassInnerClass(AnotherOuterClass); Code: 0: aload_0 1: aload_1 2: putfield #12; //Field this0: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 access0(AnotherOuterClassInnerClass); Code: 0: aload_0 1: getfield #17; //Field x:I 4: ireturn }
編譯器自動(dòng)生成了一個(gè)access$0一次來獲取x的值
AnotherOuterClass.class的反編譯結(jié)果
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 AnotherOuterClassInnerClass 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 AnotherOuterClassInnerClass."<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 AnotherOuterClassInnerClass.access0:(LAnotherOuterClassInnerClass;)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 }
其中這句話,直接說明通過內(nèi)部類的實(shí)例,獲取到私有屬性x的操作。
invokestatic #39; //Method AnotherOuterClassInnerClass.access0:(LAnotherOuterClass$InnerClass;)I
在官網(wǎng)文檔中是這樣說道的,如果(內(nèi)部類的)成員和構(gòu)造方法設(shè)定成了私有修飾符,當(dāng)且僅當(dāng)其外部類訪問時(shí)是允許的。
如何保證不被訪問
使用的方法相當(dāng)簡(jiǎn)單,使用匿名內(nèi)部類的方法實(shí)現(xiàn)
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 } }
以上就是Java private修飾符失效的原因的詳細(xì)內(nèi)容,更多關(guān)于Java private修飾符失效的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
相關(guān)文章
解決IDEA中多模塊下Mybatis逆向工程不生成相應(yīng)文件的情況
這篇文章主要介紹了解決IDEA中多模塊下Mybatis逆向工程不生成相應(yīng)文件的情況,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2021-01-01java數(shù)據(jù)結(jié)構(gòu)與算法之奇偶排序算法完整示例
這篇文章主要介紹了java數(shù)據(jù)結(jié)構(gòu)與算法之奇偶排序算法,較為詳細(xì)的分析了奇偶算法的原理并結(jié)合完整示例形式給出了實(shí)現(xiàn)技巧,需要的朋友可以參考下2016-08-08Java代碼實(shí)現(xiàn)哈希表(google 公司的上機(jī)題)
這篇文章主要介紹了Java 哈希表詳解(google 公司的上機(jī)題),本文通過圖文實(shí)例相結(jié)合給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2021-03-03springboot指定profiles啟動(dòng)失敗問題及解決
這篇文章主要介紹了springboot指定profiles啟動(dòng)失敗問題及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-04-04Java 進(jìn)程執(zhí)行外部程序造成阻塞的一種原因
前一陣子在研究文檔展示時(shí)使用了java進(jìn)程直接調(diào)用外部程序,其中遇到一個(gè)問題花了好長(zhǎng)時(shí)間才解決,這個(gè)問題就是外部程序直接執(zhí)行沒什么問題,但是當(dāng)使用Java進(jìn)程執(zhí)行時(shí)外部程序就阻塞在那兒不動(dòng)了。而且這個(gè)外部程序在處理某些文件時(shí)使用Java進(jìn)程執(zhí)行是沒問題的2014-03-03