日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

嵌套类和私有方法

發(fā)布時(shí)間:2023/12/3 编程问答 42 豆豆
生活随笔 收集整理的這篇文章主要介紹了 嵌套类和私有方法 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

當(dāng)您在另一個(gè)類中有一個(gè)類時(shí),他們可以看到彼此的private方法。 在Java開發(fā)人員中并不為人所知。 面試中的許多候選人說(shuō), private是一種可見性,它使代碼可以查看成員是否屬于同一班級(jí)。 這實(shí)際上是對(duì)的,但是更準(zhǔn)確地說(shuō),代碼和成員都在一個(gè)類中。當(dāng)我們嵌套了內(nèi)部類時(shí), private成員和使用它的代碼可能會(huì)出現(xiàn)在同一班級(jí),同時(shí)他們也處于不同的班級(jí)。

例如,如果我在一個(gè)頂級(jí)類中有兩個(gè)嵌套類,則其中一個(gè)嵌套類中的代碼可以看到另一個(gè)嵌套類的private成員。

當(dāng)我們查看生成的代碼時(shí),它開始變得很有趣。 JVM不在乎其他類中的類。 它處理JVM“頂級(jí)”類。 當(dāng)您在類A有一個(gè)名為B的類時(shí),編譯器將創(chuàng)建.class文件,其名稱將類似于A$B.class 。 B有一個(gè)可從A調(diào)用的private方法,然后JVM看到A.class中的代碼調(diào)用A$B.class的方法。 JVM檢查訪問控制。 當(dāng)我們與初級(jí)用戶討論此問題時(shí),有人建議JVM可能不在乎修飾符。 那是不對(duì)的。 嘗試編譯A.java和B.java ,兩個(gè)頂級(jí)班,在一些代碼A調(diào)用一個(gè)public的方法B 。 當(dāng)你擁有A.class和B.class修改方法B.java被public是private ,并重新編譯Bた新B.class 。 啟動(dòng)應(yīng)用程序,您將看到JVM非常關(guān)心訪問修飾符。 盡管如此,您仍可以在上面的示例中從A.class調(diào)用A$B.class的方法。

為了解決此沖突,Java生成了額外的合成方法,這些合成方法本來(lái)就是公共的,可以在同一類內(nèi)調(diào)用原始的私有方法,并且在考慮JVM訪問控制的情況下可以調(diào)用。 另一方面,如果您找出生成的方法的名稱并嘗試直接從Java源代碼中調(diào)用,則Java編譯器將不會(huì)編譯代碼。 我在4年前就寫了詳細(xì)的文章。

如果您是一位經(jīng)驗(yàn)豐富的開發(fā)人員,那么您可能會(huì)認(rèn)為這是一個(gè)奇怪而令人反感的技巧。 除了此hack外,Java非常干凈,優(yōu)雅,簡(jiǎn)潔,純凈。 還有可能是Integer緩存的破解,它使用==使小的Integer對(duì)象(典型的測(cè)試值)相等,而較大的值僅equals() ,而== (典型的生產(chǎn)值)。 但是除了合成類和Integer緩存hack之外,Java都是干凈,優(yōu)雅,簡(jiǎn)潔和純凈的。 (您可能會(huì)發(fā)現(xiàn)我是Monty Python的粉絲。)

這樣做的原因是嵌套類不是原始Java的一部分,而是僅添加到1.1版中。解決方案是一個(gè)hack,但是那時(shí)還有許多重要的事情要做,例如引入JIT編譯器,JDBC,RMI,反思和其他一些我們今天認(rèn)為理所當(dāng)然的事情。 那個(gè)時(shí)候的問題不是解決方案是否干凈。 相反,問題是Java是否將完全存活下來(lái)并成為主流編程語(yǔ)言,或者死掉并仍然是一個(gè)不錯(cuò)的嘗試。 那個(gè)時(shí)候我還擔(dān)任銷售代表,編碼只是一種業(yè)余愛好,因?yàn)闁|歐的編碼工作很少,它們主要是無(wú)聊的簿記應(yīng)用程序,而且薪水低。 那段時(shí)間有些不同,搜索引擎名為AltaVista,我們從水龍頭里喝水,而Java具有不同的優(yōu)先級(jí)。

結(jié)果是20多年來(lái),我們的JAR文件略大,Java執(zhí)行速度稍慢(除非JIT優(yōu)化了調(diào)用鏈)以及IDE中令人討厭的警告提示我們最好在嵌套類中使用包保護(hù)的方法,而不是private當(dāng)我們從頂級(jí)或其他嵌套類中使用它時(shí)。

巢主機(jī)

現(xiàn)在看來(lái),這20年的技術(shù)債務(wù)將得到解決。 http://openjdk.java.net/jeps/181進(jìn)入Java 11,它將通過引入一個(gè)新概念來(lái)解決此問題:nest。 當(dāng)前,Java字節(jié)碼包含一些有關(guān)類之間關(guān)系的信息。 JVM知道某個(gè)類是另一個(gè)類的嵌套類,而不僅僅是名稱。 該信息可以使JVM決定是否允許一個(gè)類中的一段代碼訪問另一類的private成員,但是JEP-181開發(fā)具有更一般的含義。 隨著時(shí)間的推移,JVM不再是Java虛擬機(jī)。 好吧,是的,至少它是名稱,但是,它是一個(gè)虛擬機(jī),恰好執(zhí)行從Java編譯的字節(jié)碼。 或其他語(yǔ)言的問題。 有許多針對(duì)JVM的語(yǔ)言,請(qǐng)記住JEP-181不想將JVM的新訪問控制功能與Java語(yǔ)言的特定功能聯(lián)系在一起。

JEP-181將NestHost和NestMembers的概念定義為類的屬性。 編譯器將填充這些字段,并且當(dāng)可以從另一個(gè)類訪問某個(gè)類的私有成員時(shí),JVM訪問控制可以檢查:兩個(gè)類是否在同一嵌套中? 如果它們?cè)谕怀仓?#xff0c;則允許訪問,否則不允許訪問。 我們將在反射訪問中添加方法,因此我們可以獲得嵌套中的類的列表。

簡(jiǎn)單的嵌套示例

使用

$ 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版本我們可以進(jìn)行實(shí)驗(yàn)。 我們可以創(chuàng)建一個(gè)簡(jiǎn)單的類:

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();}} }

很簡(jiǎn)單,它什么也不做。 私有方法互相調(diào)用。 沒有這個(gè),編譯器就會(huì)發(fā)現(xiàn)它們只是什么也不做,并且不需要它們,而字節(jié)碼只是不包含它們。
讀取嵌套信息的類

package nesttest;import java.util.Arrays; import java.util.stream.Collectors;public class TestNest {public static void main(String[] args) {Class host = NestingHost.class.getNestHost();Class[] nestlings = NestingHost.class.getNestMembers();System.out.println("Mother bird is: " + host);System.out.println("Nest dwellers are :\n" +Arrays.stream(nestlings).map(Class::getName).collect(Collectors.joining("\n")));} }

打印輸出符合預(yù)期:

Mother bird is: class nesttest.NestingHost Nest dwellers are : nesttest.NestingHost nesttest.NestingHost$NestedClass2 nesttest.NestingHost$NestedClass1

請(qǐng)注意,嵌套主機(jī)也列在嵌套成員中,盡管此信息應(yīng)該非常明顯且多余。 但是,這樣的使用可能允許某些語(yǔ)言從訪問中公開嵌套主機(jī)本身的私有成員,并使訪問僅允許嵌套。

字節(jié)碼

使用JDK11編譯器進(jìn)行編譯會(huì)生成文件

  • NestingHost$NestedClass1.class
  • NestingHost$NestedClass2.class
  • NestingHost.class
  • TestNest.class

沒有變化。 另一方面,如果我們使用javap反編譯器查看字節(jié)碼,則將看到以下內(nèi)容:

$ 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/NestingHost

Java 10編譯器生成access$100方法。 Java 11編譯器沒有。 相反,它在類文件中具有嵌套主機(jī)字段。 我們終于擺脫了那些在一些反映框架的代碼中列出所有方法時(shí)引起意外的綜合方法。

窩窩

讓我們玩一些布谷鳥吧。 我們可以稍微修改一下代碼,以便現(xiàn)在可以執(zhí)行以下操作:

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");}} }

我們還創(chuàng)建了一個(gè)簡(jiǎn)單的測(cè)試類

package nesttest;public class HackNest {public static void main(String[] args) { // var nestling =new NestingHost().new NestedClass1(); // nestling.publicMethod();} }

首先,從所有行的開頭刪除所有//并編譯項(xiàng)目。 它像魅力一樣工作并打印出hallo 。 之后,將生成的類復(fù)制到安全的位置,例如項(xiàng)目的根目錄。

$ cp build/classes/java/main/nesttest/NestingHost\$NestedClass1.class . $ cp build/classes/java/main/nesttest/HackNest.class .

讓我們編譯項(xiàng)目,這次使用注釋,然后將之前的編譯中的兩個(gè)類文件復(fù)制回去:

$ cp HackNest.class build/classes/java/main/nesttest/ $ cp NestingHost\$NestedClass1.class build/classes/java/main/nesttest/

現(xiàn)在我們有了一個(gè)NestingHost ,它知道它只有一個(gè)NestedClass2 : NestedClass2 。 但是,測(cè)試代碼認(rèn)為還有另一個(gè)NestedClass1 ,并且它還具有可以調(diào)用的公共方法。 這樣,我們嘗試將額外的雛鳥潛入巢中。 如果執(zhí)行代碼,則會(huì)出現(xiàn)錯(cuò)誤:

$ 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)

從代碼中認(rèn)識(shí)到導(dǎo)致錯(cuò)誤的行是我們要調(diào)用私有方法的那一行,這一點(diǎn)很重要。 Java運(yùn)行時(shí)僅在那一點(diǎn)而不是更快地進(jìn)行檢查。

我們喜歡還是不喜歡? 快速失敗原則在哪里? 為什么Java運(yùn)行時(shí)僅在非常需要時(shí)才開始執(zhí)行類并檢查嵌套結(jié)構(gòu)? 原因,在Java情況下,原因很多:向后兼容。 加載所有類后,JVM可以檢查嵌套結(jié)構(gòu)的一致性。 這些類僅在使用時(shí)加載。 可以更改Java 11中的類加載,并與嵌套主機(jī)一起加載所有嵌套的類,但是這會(huì)破壞向后兼容性。 如果沒有別的,懶惰的單例模式會(huì)崩潰,我們不希望那樣。 我們愛單身,但只有單麥芽(是)。

結(jié)論

JEP-181是Java的一個(gè)小改動(dòng)。 大多數(shù)開發(fā)人員甚至不會(huì)注意到。 它消除了技術(shù)債務(wù),如果核心Java項(xiàng)目沒有消除技術(shù)債務(wù),那么我們對(duì)普通開發(fā)人員有何期待?

就像古老的拉丁語(yǔ)所說(shuō):“技術(shù)需要借記卡。”

翻譯自: https://www.javacodegeeks.com/2018/08/nested-classes-private-methods.html

總結(jié)

以上是生活随笔為你收集整理的嵌套类和私有方法的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。