c++ 嵌套私有类_嵌套类和私有方法
c++ 嵌套私有類
當您在另一個類中有一個類時,他們可以看到彼此的private方法。 在Java開發人員中并不為人所知。 面試過程中的許多候選人說, private是一種可見性,它使代碼可以查看成員是否屬于同一班級。 這實際上是對的,但更準確地說,代碼和成員都在一個類中。當我們嵌套了內部類時, private成員和使用它的代碼可能會出現在同一班級,同時他們也處于不同的班級。
例如,如果我在一個頂級類中有兩個嵌套類,則其中一個嵌套類中的代碼可以看到另一個嵌套類的private成員。
當我們查看生成的代碼時,它開始變得很有趣。 JVM不在乎其他類中的類。 它處理JVM“頂級”類。 當您在類A有一個名為B的類時,編譯器將創建.class文件,其名稱將類似于A$B.class 。 B有一個可從A調用的private方法,然后JVM看到A.class中的代碼調用A$B.class的方法。 JVM檢查訪問控制。 當我們與初級用戶討論此問題時,有人建議JVM可能不在乎修飾符。 那是不對的。 嘗試編譯A.java和B.java ,兩個頂級班,在一些代碼A調用一個public的方法B 。 當你擁有A.class和B.class修改方法B.java被public是private ,并重新編譯Bた新B.class 。 啟動應用程序,您將看到JVM非常關心訪問修飾符。 不過,您仍可以在上面的示例中從A.class調用A$B.class的方法。
為了解決此沖突,Java生成了一些固有的公共合成方法,請在同一類中調用原始的私有方法,并且在考慮JVM訪問控制的情況下可以調用該方法。 另一方面,如果您找出生成的方法的名稱并嘗試直接從Java源代碼中調用,則Java編譯器將不會編譯代碼。 我在4年前就寫了詳細的文章。
如果您是一位經驗豐富的開發人員,那么您可能會認為這是一個奇怪而令人反感的技巧。 除了此hack之外,Java如此干凈,優雅,簡潔,純凈。 還有可能是Integer高速緩存的破解,它使用==使小的Integer對象(典型的測試值)相等,而較大的值只是equals()而不是== (典型的生產值)。 但是除了合成類和Integer緩存hack之外,Java都是干凈,優雅,簡潔和純凈的。 (您可能會發現我是Monty Python的粉絲。)
這樣做的原因是嵌套類不是原始Java的一部分,而是僅添加到1.1版中。解決方案是一個hack,但是那時還有很多重要的事情要做,例如引入JIT編譯器,JDBC,RMI,反思和其他一些我們今天認為理所當然的事情。 那時的問題不是解決方案是否干凈。 相反,問題是Java是否將完全存活下來并成為主流編程語言或死掉,并且仍然是一個不錯的嘗試。 那個時候我還擔任銷售代表,而編碼只是一種愛好,因為東歐的編碼工作很少,它們主要是無聊的簿記應用程序,而且薪水低。 那段時間有些不同,搜索引擎名為AltaVista,我們從水龍頭里喝水,而Java具有不同的優先級。
結果是20多年來,我們的JAR文件略大,Java執行速度稍慢(除非JIT優化了調用鏈)以及IDE中令人討厭的警告提示我們最好在嵌套類中使用包保護的方法,而不是private當我們從頂級或其他嵌套類中使用它時。
巢主機
現在看來,這20年的技術債務將得到解決。 http://openjdk.java.net/jeps/181進入Java 11,它將通過引入一個新概念嵌套來解決此問題。 當前,Java字節碼包含一些有關類之間關系的信息。 JVM知道某個類是另一個類的嵌套類,而不僅僅是名稱。 該信息可以幫助JVM決定一個類中的一段代碼是允許還是不允許訪問另一類的private成員,但是JEP-181開發有一些更通用的方法。 隨著時間的推移,JVM不再是Java虛擬機。 好吧,是的,至少是它的名字,但是,它是一個虛擬機,恰好執行從Java編譯的字節碼。 或其他語言的問題。 有許多針對JVM的語言,請記住,JEP-181不想將JVM的新訪問控制功能與Java語言的特定功能聯系在一起。
JEP-181將NestHost和NestMembers的概念定義為類的屬性。 編譯器將填充這些字段,并且當可以從其他類訪問某個類的私有成員時,JVM訪問控制可以檢查:這兩個類是否在同一嵌套中? 如果它們在同一巢中,則允許訪問,否則不允許訪問。 我們將在反射訪問中添加方法,因此我們可以獲得嵌套中的類的列表。
簡單的嵌套示例
使用
$ java -version java version "11-ea" 2018-09-25 Java(TM) SE Runtime Environment 18.9 (build 11-ea+25) Java HotSpot(TM) 64-Bit Server VM 18.9 (build 11-ea+25, mixed mode)今天我們可以進行Java版本的實驗。 我們可以創建一個簡單的類:
package nesttest; public class NestingHost {public static class NestedClass1 {private void privateMethod() {new NestedClass2().privateMethod();}}public static class NestedClass2 {private void privateMethod() {new NestedClass1().privateMethod();}} } 很簡單,它什么也不做。 私有方法互相調用。 沒有這個,編譯器就會發現它們只是什么也不做,不需要它們,而字節碼只是不包含它們。
讀取嵌套信息的類
打印輸出符合預期:
Mother bird is: class nesttest.NestingHost Nest dwellers are : nesttest.NestingHost nesttest.NestingHost$NestedClass2 nesttest.NestingHost$NestedClass1請注意,嵌套主機也列在嵌套成員中,盡管此信息應該非常明顯且多余。 但是,這樣的使用可能允許某些語言從訪問中公開嵌套主機本身的私有成員,并使訪問僅允許嵌套。
字節碼
使用JDK11編譯器進行編譯會生成文件
- NestingHost$NestedClass1.class
- NestingHost$NestedClass2.class
- NestingHost.class
- TestNest.class
沒有變化。 另一方面,如果我們使用javap反編譯器查看字節碼,則將看到以下內容:
$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class Classfile .../packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.classLast modified Aug 6, 2018; size 557 bytesMD5 checksum 5ce1e0633850dd87bd2793844a102c52Compiled from "NestingHost.java" public class nesttest.NestingHost$NestedClass1minor version: 0major version: 55flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #5 // nesttest/NestingHost$NestedClass1super_class: #6 // java/lang/Objectinterfaces: 0, fields: 0, methods: 2, attributes: 3 Constant pool:*** CONSTANT POOL DELETED FROM THE PRINTOUT ***{public nesttest.NestingHost$NestedClass1();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lnesttest/NestingHost$NestedClass1; } SourceFile: "NestingHost.java" NestHost: class nesttest/NestingHost InnerClasses:public static #13= #5 of #20; // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHostpublic static #23= #2 of #20; // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHost如果我們使用JDK10編譯器編譯相同的類,則反匯編行如下:
$ javap -v build/classes/java/main/nesttest/NestingHost\$NestedClass1.class Classfile /C:/Users/peter_verhas/Dropbox/packt/Fundamentals-of-java-18.9/sources/ch08/bulkorders/build/classes/java/main/nesttest/NestingHost$NestedClass1.classLast modified Aug 6, 2018; size 722 bytesMD5 checksum 8c46ede328a3f0ca265045a5241219e9Compiled from "NestingHost.java" public class nesttest.NestingHost$NestedClass1minor version: 0major version: 54flags: (0x0021) ACC_PUBLIC, ACC_SUPERthis_class: #6 // nesttest/NestingHost$NestedClass1super_class: #7 // java/lang/Objectinterfaces: 0, fields: 0, methods: 3, attributes: 2 Constant pool:*** CONSTANT POOL DELETED FROM THE PRINTOUT ***{public nesttest.NestingHost$NestedClass1();descriptor: ()Vflags: (0x0001) ACC_PUBLICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #2 // Method java/lang/Object."<init>":()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 this Lnesttest/NestingHost$NestedClass1;static void access$100(nesttest.NestingHost$NestedClass1);descriptor: (Lnesttest/NestingHost$NestedClass1;)Vflags: (0x1008) ACC_STATIC, ACC_SYNTHETICCode:stack=1, locals=1, args_size=10: aload_01: invokespecial #1 // Method privateMethod:()V4: returnLineNumberTable:line 6: 0LocalVariableTable:Start Length Slot Name Signature0 5 0 x0 Lnesttest/NestingHost$NestedClass1; } SourceFile: "NestingHost.java" InnerClasses:public static #14= #6 of #25; // NestedClass1=class nesttest/NestingHost$NestedClass1 of class nesttest/NestingHostpublic static #27= #3 of #25; // NestedClass2=class nesttest/NestingHost$NestedClass2 of class nesttest/NestingHostJava 10編譯器生成access$100方法。 Java 11編譯器沒有。 相反,它在類文件中具有嵌套主機字段。 我們終于擺脫了那些在某些反映框架的代碼中列出所有方法時引起意外的綜合方法。
窩窩
讓我們玩一些布谷鳥。 我們可以稍微修改一下代碼,以便現在可以執行以下操作:
package nesttest; public class NestingHost { // public class NestedClass1 { // public void publicMethod() { // new NestedClass2().privateMethod(); /* <-- this is line 8 */ // } // }public class NestedClass2 {private void privateMethod() {System.out.println("hallo");}} }我們還創建了一個簡單的測試類
package nesttest;public class HackNest {public static void main(String[] args) { // var nestling =new NestingHost().new NestedClass1(); // nestling.publicMethod();} }首先,從所有行的開頭刪除所有//并編譯項目。 它像魅力一樣工作并打印出hallo 。 之后,將生成的類復制到安全的位置,例如項目的根目錄。
$ cp build/classes/java/main/nesttest/NestingHost\$NestedClass1.class . $ cp build/classes/java/main/nesttest/HackNest.class .讓我們編譯項目,這次添加注釋,然后復制回上一次編譯中的兩個類文件:
$ cp HackNest.class build/classes/java/main/nesttest/ $ cp NestingHost\$NestedClass1.class build/classes/java/main/nesttest/現在我們有了一個NestingHost ,它知道它只有一個NestedClass2 : NestedClass2 。 但是,測試代碼認為還有另一個NestedClass1 ,并且它還具有可以調用的公共方法。 這樣,我們嘗試將額外的雛鳥潛入巢中。 如果執行代碼,則會出現錯誤:
$ java -cp build/classes/java/main/ nesttest.HackNest Exception in thread "main" java.lang.IncompatibleClassChangeError: Type nesttest.NestingHost$NestedClass1 is not a nest member of nesttest.NestingHost: current type is not listed as a nest memberat nesttest.NestingHost$NestedClass1.publicMethod(NestingHost.java:8)at nesttest.HackNest.main(HackNest.java:7)從代碼中識別出導致錯誤的行是我們要調用私有方法的那一行,這一點很重要。 Java運行時僅在那時而不是更早執行檢查。
我們喜歡還是不喜歡? 快速失敗原則在哪里? 為什么Java運行時僅在非常需要時才開始執行類并檢查嵌套結構? 在Java中,原因很多:向后兼容。 加載所有類后,JVM可以檢查嵌套結構的一致性。 這些類僅在使用時加載。 可以更改Java 11中的類加載,并與嵌套主機一起加載所有嵌套類,但是這樣做會破壞向后兼容性。 如果沒有別的,懶惰的單例模式會崩潰,我們不希望那樣。 我們愛單身,但只有單麥芽(是)。
結論
JEP-181是Java的一個小改動。 大多數開發人員甚至不會注意到。 它消除了技術債務,如果核心Java項目沒有消除技術債務,那么我們對普通開發人員有什么期望?
就像古老的拉丁語所說:“技術需要借記卡。”
翻譯自: https://www.javacodegeeks.com/2018/08/nested-classes-private-methods.html
c++ 嵌套私有類
總結
以上是生活随笔為你收集整理的c++ 嵌套私有类_嵌套类和私有方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: ps怎么删除智能对象(ps怎么删除智能对
- 下一篇: ddos攻击端口(ddos创建端口)