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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

Java知识总结(五)

發(fā)布時(shí)間:2024/1/1 java 21 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java知识总结(五) 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

JAVA BIO/NIO

同步

發(fā)起一個(gè)請(qǐng)求或任務(wù),被調(diào)用者在未完成請(qǐng)求或任務(wù)前,不會(huì)返回結(jié)果。

需要一直等待該請(qǐng)求返回或任務(wù)完成反饋的結(jié)果,在這期間不能夠去做其他的事情。

比如:你打電話給書店老板詢問(wèn)書籍,老板幫你去找書,你需要一直等待,等待書店老板給你回復(fù)。

異步

發(fā)起一個(gè)請(qǐng)求或任務(wù)之后,被調(diào)用者會(huì)理刻返回表示已經(jīng)接受請(qǐng)求或任務(wù),但是并沒(méi)有返回結(jié)果,就接著去做別的事情,發(fā)出的請(qǐng)求或任務(wù)完成時(shí),被調(diào)用者會(huì)返回結(jié)果。

比如:你打電話給書店老板詢問(wèn)書籍,你讓他查到了再打電話給你,然后你掛斷電話,期間你可以干其他事情,等到老本找到了書籍然后給你打電話。

阻塞

發(fā)起請(qǐng)求后,調(diào)用者需要一直等待結(jié)果返回,也就是當(dāng)前的線程會(huì)被掛起,無(wú)法去做其他請(qǐng)求。

非阻塞

發(fā)起請(qǐng)求后,調(diào)用者不需要等待結(jié)果返回,可以去做別的事情。

BIO(Blocking I/O)(最傳統(tǒng)的同步阻塞IO模型)

典型的同步阻塞IO模型:data = socket.read();

當(dāng)應(yīng)用程序發(fā)出請(qǐng)求時(shí),先去判斷內(nèi)核中的數(shù)據(jù)是否準(zhǔn)備完成,如果沒(méi)有準(zhǔn)備完成,該應(yīng)用程序就會(huì)被阻塞(讓出cpu資源),等到內(nèi)核數(shù)據(jù)準(zhǔn)備完成,將數(shù)據(jù)拷貝給應(yīng)用程序,應(yīng)用程序解除block狀態(tài)。

基于字節(jié)流和字符流操作,數(shù)據(jù)流的特點(diǎn)是單向性,要么只讀、要么只寫。

server端要為每一個(gè)連接建立一個(gè)線程,這樣的好處是每個(gè)線程可以專注自身的I/O操作并且編程簡(jiǎn)單。但是這種模型并不適合連接數(shù)過(guò)多情況。

NIO(Non - Blocking I/O)(同步非阻塞IO模型)

當(dāng)應(yīng)用程序發(fā)出read請(qǐng)求后,不需要等待,它會(huì)馬上得到來(lái)自內(nèi)核的返回,如果返回的結(jié)果是error(數(shù)據(jù)沒(méi)有準(zhǔn)備好),那么應(yīng)用程序就繼續(xù)向內(nèi)核發(fā)出請(qǐng)求,再次去確認(rèn),這樣不停做循環(huán),一旦內(nèi)核準(zhǔn)好數(shù)據(jù)同時(shí)應(yīng)用程序發(fā)來(lái)請(qǐng)求,那么就將數(shù)據(jù)拷貝給應(yīng)用程序,返回。

這樣帶來(lái)的問(wèn)題:線程沒(méi)有進(jìn)入阻塞狀態(tài),它就不會(huì)讓出cpu資源,導(dǎo)致cpu的占用率很高。

NIO的組成包括:Channel(通道)、 Buffer(緩沖區(qū))、Selector

Channel

  • Channel和Stream()是同一個(gè)級(jí)別的,區(qū)別在于:Stream是單向的,而Channel是雙向的,既可以用來(lái)讀也可以用來(lái)寫操作。

  • Channel的主要實(shí)現(xiàn):

  • FileChannel
  • DatagramChannel
  • SocketChannel
  • ServerSocketChannel
  • 1對(duì)應(yīng)文件IO、2對(duì)應(yīng)文件UDP、3、4對(duì)應(yīng)文件TCP(Server和 Client)

  • Buffer

    是一個(gè)容器,連續(xù)的數(shù)組用來(lái)存儲(chǔ)數(shù)據(jù)。

    Channel提供從文件、網(wǎng)絡(luò)讀取數(shù)據(jù)的渠道,但是讀寫操作都必須由Buffer來(lái)操作。

    上面是一個(gè)從客戶端向服務(wù)器端發(fā)送數(shù)據(jù)的過(guò)程。

    客戶端發(fā)出數(shù)據(jù)經(jīng)過(guò)Buffer寫入傳給Channel,讀入數(shù)據(jù)經(jīng)過(guò)Channel將數(shù)據(jù)讀入Buffer傳給服務(wù)端。

  • Selector

    是NIO的核心類,通過(guò)Selector去檢測(cè)多個(gè)Channel中是否有數(shù)據(jù)的發(fā)生(讀或?qū)懻?qǐng)求),如果對(duì)應(yīng)的Channel上有真正的請(qǐng)求發(fā)生,那么就去處理該Channel上的請(qǐng)求。Selector本身也是一個(gè)線程,設(shè)定一個(gè)線程專門去管理多個(gè)Channel的請(qǐng)求任務(wù),而不需要為每一個(gè)Channel去建立對(duì)應(yīng)的線程,避免了多個(gè)線程之間的上下文切換,大大減少了系統(tǒng)的開銷。

多路復(fù)用IO模型

此模型的本質(zhì)還是NIO模型,在NIO中的通過(guò)Selector實(shí)現(xiàn)在一個(gè)線程輪詢多個(gè)通道的數(shù)據(jù),需要先將用戶線程中需要輪詢的socket注冊(cè)到Selector中,用Selector去輪詢多個(gè)socketChannel是否有請(qǐng)求到達(dá),一旦請(qǐng)求到達(dá),Selector.select返回,最后完成I/O數(shù)據(jù)的傳輸這個(gè)過(guò)程用戶線程是處于阻塞狀態(tài)的。注意:socket配置也是非阻塞的。

相比于NIO,多路復(fù)用IO用戶線程首先需要在Reactor中注冊(cè)一個(gè)事件處理器,然后Reactor(相當(dāng)于上文提到的selector)負(fù)責(zé)輪詢各個(gè)通道是否有新的數(shù)據(jù)到來(lái),當(dāng)有新的數(shù)據(jù)到來(lái)時(shí),Reactor通過(guò)先前注冊(cè)的事件處理器通知用戶線程有數(shù)據(jù)可讀,此時(shí)用戶線程向內(nèi)核發(fā)起讀取IO數(shù)據(jù)的請(qǐng)求,用戶線程阻塞直至數(shù)據(jù)讀取完成。

多路復(fù)用IO模型效率高于NIO模型原因在于:NIO中socket輪詢是在用戶線程中的,而多路復(fù)用是在內(nèi)核中。

信號(hào)驅(qū)動(dòng)IO模型

當(dāng)用戶線程發(fā)起一個(gè)I/O請(qǐng)求時(shí),給對(duì)應(yīng)的socket注冊(cè)一個(gè)信號(hào)函數(shù),用戶不會(huì)立刻得到結(jié)果(內(nèi)核中數(shù)據(jù)還沒(méi)有準(zhǔn)備好),而是繼續(xù)去做別的事情,當(dāng)內(nèi)核中數(shù)據(jù)準(zhǔn)備號(hào)時(shí),給用戶發(fā)送一個(gè)信號(hào)給用戶線程,用戶線程通過(guò)在信號(hào)函數(shù)中調(diào)用I/O操作進(jìn)行實(shí)際的讀寫操作。

異步IO模型

該模型是最理想模型。它實(shí)現(xiàn)的流程:當(dāng)用戶線程發(fā)起read操作之后,就去做它自己的事情了,內(nèi)核接收到用戶線程的請(qǐng)求后,立刻返回,表明該請(qǐng)求已經(jīng)受理,這個(gè)過(guò)程不會(huì)對(duì)用戶線程造成任何阻塞。因?yàn)閮?nèi)核在完成數(shù)據(jù)準(zhǔn)備后就將數(shù)據(jù)拷貝給用戶線程,返回用戶線程信息表明數(shù)據(jù)已經(jīng)傳輸完畢,read操作已經(jīng)完成,不需要用戶線程再去調(diào)用IO操作。只需要先發(fā)起一個(gè)請(qǐng)求,當(dāng)接收內(nèi)核返回的成功信號(hào)時(shí)表示 IO 操作已經(jīng)完成,可以直接去使用數(shù)據(jù)了。

和信號(hào)驅(qū)動(dòng)模型的差別就在這里,信號(hào)驅(qū)動(dòng)模型在內(nèi)核完成數(shù)據(jù)準(zhǔn)備之后,告訴用戶線程數(shù)據(jù)已經(jīng)準(zhǔn)備完畢,需要你自己來(lái)調(diào)用IO操作拿到數(shù)據(jù)。


Java IO

IO分類

  • 按照流的流向分,可以分為輸?流和輸出流;
  • 按照操作單元?jiǎng)澐?#xff0c;可以劃分為字節(jié)流和字符流;
  • 按照流的??劃分為節(jié)點(diǎn)流和處理流。

InputStream/Reader: 所有的輸?流的基類,前者是字節(jié)輸?流,后者是字符輸?流。

OutputStream/Writer: 所有輸出流的基類,前者是字節(jié)輸出流,后者是字符輸出流。

不管是文件讀寫還是網(wǎng)絡(luò)發(fā)送接收,信息的最小存儲(chǔ)單元都是字節(jié),那為什么I/O流操作要分為字節(jié)流操作和字符流操作呢?

字符流是由 Java 虛擬機(jī)將字節(jié)轉(zhuǎn)換得到的,問(wèn)題就出在這個(gè)過(guò)程還算是?常耗時(shí),并且,如果我們不知道編碼類型就很容易出現(xiàn)亂碼問(wèn)題。所以, I/O 流就?脆提供了?個(gè)直接操作字符的接??便我們平時(shí)對(duì)字符進(jìn)?流操作。


JVM類加載機(jī)制

Java程序運(yùn)行時(shí),必須經(jīng)過(guò)編譯和運(yùn)行兩個(gè)步驟。首先將后綴名為.java的源文件進(jìn)行編譯,最終生成后綴名為.class的字節(jié)碼文件。然后Java虛擬機(jī)將編譯好的字節(jié)碼文件加載到內(nèi)存(這個(gè)過(guò)程被稱為類加載,是由加載器完成的),然后虛擬機(jī)針對(duì)加載到內(nèi)存的java類進(jìn)行解釋執(zhí)行,顯示結(jié)果。

JVM類加載大致分為三個(gè)過(guò)程:加載、連接、初始化

類加載器

在類加載的過(guò)程中,只有加載階段可以自定義類加載器,而其他階段由JVM主導(dǎo)。

因此加載的階段被放到了JVM外部實(shí)現(xiàn),便于讓應(yīng)用程序決定如何獲取所需的類。

JVM中提供了三種類加載器:

  • 啟動(dòng)類加載器(Bootstrap ClassLoader)

    最頂層的類加載器,由c++實(shí)現(xiàn)。

    負(fù)責(zé)加載:JAVA_HOME\lib 目錄中的jar包或被 -Xbootclasspath 參數(shù)指定的路徑中的所有類

  • 擴(kuò)展類加載器(Extension ClassLoader)

    繼承自:java.lang.ClassLoader

    負(fù)責(zé)加載 JAVA_HOME\lib\ext 目錄中的,或通過(guò) java.ext.dirs 系統(tǒng)變量指定路徑中的類庫(kù)。

  • 應(yīng)用程序類加載器(Application ClassLoader/ System Class Loader ):

    (這里的Application ClassLoader 和System Class Loader 是同一個(gè)類加載器,只是叫法不同)

    繼承自:java.lang.ClassLoader

    ?向我們?戶的加載器,負(fù)責(zé)加載當(dāng)前應(yīng)?classpath下的所有jar包和類。

可以通過(guò)繼承 java.lang.ClassLoader實(shí)現(xiàn)自定義的類加載器,重寫findClass方法加載指定路徑上的class。

雙親委派模型

每一個(gè)類都有對(duì)應(yīng)的類加載器。當(dāng)類收到一個(gè)加載請(qǐng)求時(shí),先去判斷這個(gè)類是否已經(jīng)被加載,被加載過(guò)的類會(huì)直接返回,否則嘗試加載。

加載過(guò)程:類本身不會(huì)主動(dòng)去加載,它會(huì)將請(qǐng)求委派給父類加載器loadClass()處理,父類則會(huì)委派給父類的父類,因此所有的請(qǐng)求都會(huì)傳到頂層的類加載器中(Bootstrap ClassLoader),只有當(dāng)父類中的加載器無(wú)法進(jìn)行加載時(shí),自己才會(huì)來(lái)處理類加載。

注意:類加載器之間的“??”關(guān)系也不是通過(guò)繼承來(lái)體現(xiàn)的,是由“優(yōu)先級(jí)”來(lái)決定

//源碼private final ClassLoader parent;protected Class<?> loadClass(String name, boolean resolve)throws ClassNotFoundException{synchronized (getClassLoadingLock(name)) {// ?先,檢查請(qǐng)求的類是否已經(jīng)被加載過(guò)Class<?> c = findLoadedClass(name);if (c == null) {long t0 = System.nanoTime();try {if (parent != null) {//?加載器不為空,調(diào)??加載loadClass()?法處理c = parent.loadClass(name, false);} else {//?加載器為空,使?啟動(dòng)類加載器BootstrapClassLoader 加載c = findBootstrapClassOrNull(name);}} catch (ClassNotFoundException e) {//拋出異常說(shuō)明?類加載器?法完成加載請(qǐng)求}if (c == null) {long t1 = System.nanoTime();//??嘗試加載c = findClass(name);// this is the defining class loader; record thestatssun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0);sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t1);sun.misc.PerfCounter.getFindClasses().increment();}}if (resolve) {resolveClass(c);}return c;}}

好處:避免類的重復(fù)加載(JVM 區(qū)分不同類的方式不僅僅根據(jù)類名,相同的類文件被不同的類加載器加載產(chǎn)生的是兩個(gè)不同的類)

比如:加載rs.jar包中的類java.lang.Object,無(wú)論加載器加載那個(gè)類,最終委派給啟動(dòng)類加載器進(jìn)行類的加載,保證了不同的類加載器最終得到的是同一個(gè)Ojbect對(duì)象。

連接的過(guò)程在細(xì)分為:驗(yàn)證、準(zhǔn)備、解析

  • 加載

    這個(gè)階段會(huì)在內(nèi)存中生成代表該類的java.lang.Class對(duì)象(類對(duì)象),作為方法區(qū)這個(gè)類的各種數(shù)據(jù)的入口。

    注意:獲取類的過(guò)程并不一定要從Class文件中,也可以從jar包或war包中獲取,也可以運(yùn)行時(shí)計(jì)算生成(動(dòng)態(tài)代理)。

  • 連接

    • 驗(yàn)證

      確保class文件的字節(jié)流中的信息符合JVM的要求,不會(huì)危害JVM的安全

    • 準(zhǔn)備

      正式為類中的變量分配內(nèi)存以及為其設(shè)置初始值階段(在方法區(qū)中為這些類變量分配內(nèi)存)。

      舉例:

      public static int v = 8080; /* 定義的靜態(tài)變量 v 這里初始化值的過(guò)程并不是直接將 8080 賦值給 v ,v 變量在準(zhǔn)備階段的初始化值是 0 , 將其賦值為 8080 的是put static 指令,該指令被編譯后存放在類構(gòu)造器<client>方法中。 */public final static int v = 8080; /* 如果聲明靜態(tài)變量被final關(guān)鍵字所修飾,在編譯階段生成的v 的ConstantValue屬性,在準(zhǔn)備階段中v被賦值為 8080 */
    • 解析

      JVM將常量池中符號(hào)引用替換直接引用的過(guò)程。

      • 符號(hào)引用

        一組符號(hào)所描述的引用目標(biāo),符號(hào)的形式是字面量。

        如:在Class文件中它以CONSTANT_Class_info、CONSTANT_Field_info、CONSTANT_Method_info等類型的常量出現(xiàn)。

        在Java中,一個(gè)java類將會(huì)編譯成一個(gè)class文件。在編譯時(shí),java類并不知道所引用的變量(基本數(shù)據(jù)類型、局部變量、方法等等)實(shí)際地址因此只能使用符號(hào)引用來(lái)代替。比如org.simple.People類引用了org.simple.Language類,在編譯時(shí)People類并不知道Language類的實(shí)際內(nèi)存地址,因此只能使用符號(hào)org.simple.Language。

        各種JVM實(shí)現(xiàn)內(nèi)存的布局可能不同,但是它們識(shí)別符號(hào)引用是一致的。

      • 直接引用

        指向目標(biāo)的指針,相對(duì)偏移量(指向?qū)嵗兞俊?shí)例方法的直接引用都是偏移量),間接定位到目標(biāo)的句柄。

        直接引用與JVM布局有關(guān),同一個(gè)符號(hào)引用在不同的虛擬機(jī)實(shí)例上翻譯出來(lái)的直接引用一般不會(huì)相同。

        如果有了直接引用,那目標(biāo)必定存在于內(nèi)存中。

  • 初始化

    類加載的最后一個(gè)階段,除了在類加載階段可以自定義類加載器,其他的階段都是由JVM主導(dǎo)控制。

    這個(gè)階段才是正真的執(zhí)行字節(jié)碼文件,根據(jù)字節(jié)碼文件的內(nèi)容對(duì)類的各個(gè)字段進(jìn)行賦值。

類構(gòu)造器

初始化階段是類構(gòu)造器方法執(zhí)行的過(guò)程,方法是由編譯器收集類中的類變量賦值操作和靜態(tài)代碼塊合成的,JVM會(huì)保證方法執(zhí)行前其父類的方法已經(jīng)執(zhí)行完畢。如果一個(gè)類中沒(méi)有靜態(tài)變量、靜態(tài)語(yǔ)句塊,那么編譯器可以不為這個(gè)類生成方法

Java對(duì)象創(chuàng)建的過(guò)程

對(duì)象的創(chuàng)建分為五個(gè)過(guò)程

  • 類加載檢查

    當(dāng)JVM接收到new指令時(shí),首先會(huì)先去檢查該指令能否在常量池中找到對(duì)應(yīng)該類的符號(hào)引用,并檢查該類是否已經(jīng)被加載、連接,初始化過(guò)。如果沒(méi)有先進(jìn)行類的加載。

  • 分配內(nèi)存

    在類加載檢查完成后,在java堆中為新生的對(duì)象分配內(nèi)存。

    分配內(nèi)存方式有兩種:指針碰撞、空閑列表。

    分配方式選擇根據(jù):java堆內(nèi)存是否規(guī)整

    指針碰撞

    • 適用場(chǎng)景:java堆內(nèi)存規(guī)整(沒(méi)有內(nèi)存碎片化)
    • GC收集器:Serial (單線程、復(fù)制算法)和 PerNew(多線程、復(fù)制算法)。
    • 原理:將內(nèi)存分為兩塊,中間有一個(gè)分界值指針,用過(guò)的內(nèi)存放一邊,沒(méi)有用過(guò)的內(nèi)存放一邊,將對(duì)象放入到?jīng)]有用過(guò)的內(nèi)存中

    空閑列表:

    • 適用場(chǎng)景:Java堆內(nèi)存碎片化
    • GC收集器:CMS(多線程+標(biāo)記清除算法)
    • 原理:將列表中沒(méi)有用過(guò)的內(nèi)存標(biāo)記下來(lái),找到適合新生對(duì)象大小的位置放入即可,更新列表。

    分配內(nèi)存需要考慮到線程安全的問(wèn)題:

    對(duì)象的創(chuàng)建很頻繁,因此JVM需要保證線程的安全:

    • TLAB:為每個(gè)線程預(yù)先在Eden區(qū)分配一塊內(nèi)存,JVM給對(duì)象分配內(nèi)存時(shí)先在TLAB中分配,當(dāng)TLAB中內(nèi)存不夠或者使用完之后,就采用CAS+失敗重試的方法。
    • CAS+失敗重試:CAS 是樂(lè)觀鎖的一種實(shí)現(xiàn)方式。樂(lè)觀鎖:每次不加鎖而是假設(shè)沒(méi)有沖突去完成某個(gè)操作,如果因?yàn)闆_突失敗就重試,直到成功為止。此方法保證更新操作的原子性
  • 初始化零值

    內(nèi)存分配完成后,JVM將分配到的內(nèi)存空間初始化零值(不包含對(duì)象頭),這一操作保證了對(duì)象中的成員變量在不賦初值就可以使用。

  • 設(shè)置對(duì)象頭

    對(duì)象頭中的信息包含:

markword(標(biāo)記字段)

  • 對(duì)象的哈希碼
  • 對(duì)象對(duì)應(yīng)的GC分代年齡
  • 鎖狀態(tài)標(biāo)志、線程持有的鎖、

klass(Class對(duì)象指針)

  • 對(duì)象指向它的類元數(shù)據(jù)的指針,虛擬機(jī)通過(guò)這個(gè)指針來(lái)確定這個(gè)對(duì)象是哪個(gè)類的實(shí)例

數(shù)組長(zhǎng)度(只有數(shù)組對(duì)象有)
如果對(duì)象是一個(gè)數(shù)組, 那在對(duì)象頭中還必須有一塊數(shù)據(jù)用于記錄數(shù)組長(zhǎng)度(例如:int)。

  • 執(zhí)行構(gòu)造方法

    從JVM角度來(lái)看一個(gè)對(duì)象已經(jīng)產(chǎn)生,從java程序角度來(lái)看,創(chuàng)建對(duì)象才開始,執(zhí)行構(gòu)造方法,按照意愿將對(duì)象初始化數(shù)據(jù)之后這個(gè)對(duì)象才能夠真正得到使用。

圖上有點(diǎn)小錯(cuò)誤:分配內(nèi)存中:采用指針碰撞是復(fù)制算法,不是標(biāo)記整理

??蜕献龅降念}目:

(單選題)以下代碼的輸出結(jié)果是?public class B{public static B t1 = new B();public static B t2 = new B();{System. out.println( "構(gòu)造塊");}static{System.out.println("靜態(tài)塊");}public static void main( String[] args){B t = new B( );}}//正確答案:構(gòu)造塊、構(gòu)造塊、靜態(tài)塊、構(gòu)造塊 //現(xiàn)從主函數(shù)Main中入手,執(zhí)行 B t = new B( );也就是創(chuàng)建對(duì)象,創(chuàng)建對(duì)象之前需要先進(jìn)行類加載過(guò)程,而類加載的過(guò)程需要檢查類是否進(jìn)行加載,現(xiàn)在進(jìn)行類的加載過(guò)程。 /*類中定義了靜態(tài)域:靜態(tài)變量,靜態(tài)代碼塊,靜態(tài)方法。 靜態(tài)域執(zhí)行的過(guò)程:按照其定義的變量、代碼塊、方法的順序來(lái)。 因此這里先執(zhí)行public static B t1 = new B();這個(gè)代碼,而這也是創(chuàng)建對(duì)象的語(yǔ)句,創(chuàng)建對(duì)象之前也是需要進(jìn)行類加載檢查,而B類在前就已經(jīng)加載過(guò)了,注意:類中的靜態(tài)域只在類第一次加載的過(guò)程中執(zhí)行,因此這里不會(huì)再在進(jìn)行靜態(tài)域的加載,跳過(guò)靜態(tài)域到構(gòu)造塊和構(gòu)造方法的執(zhí)行過(guò)程,完成t1對(duì)象創(chuàng)建,因此控制臺(tái)輸出:構(gòu)造塊。 接著回到 public static B t2 = new B();的過(guò)程,繼續(xù)創(chuàng)建對(duì)象t2,這個(gè)過(guò)程和t1是一樣的因此,輸出:構(gòu)造塊。當(dāng)兩個(gè)靜態(tài)變量都完成時(shí),接下來(lái)執(zhí)行靜態(tài)代碼塊,輸出:靜態(tài)塊。 執(zhí)行構(gòu)造塊和構(gòu)造方法,最后創(chuàng)建對(duì)象t,輸出:構(gòu)造塊。 */

對(duì)象訪問(wèn)定位的兩種方式

建立對(duì)象之后就是要調(diào)用對(duì)象干事,java中通過(guò)棧上的reference數(shù)據(jù)來(lái)操作堆上的具體對(duì)象。

  • 句柄

    在java堆中開辟一塊內(nèi)存用作句柄池,句柄本身是指向?qū)ο蟮膶?shí)例數(shù)據(jù)和類型數(shù)據(jù),引用是指向句柄。

  • 直接指針

通過(guò)指針直接指向java堆中對(duì)象的地址,堆中對(duì)象的布局有所改變,在對(duì)象的實(shí)例數(shù)據(jù)中存放指向?qū)ο箢愋蛿?shù)據(jù)的地址。

句柄訪問(wèn)對(duì)象的好處就是:當(dāng)對(duì)象的地址改變時(shí),引用的地址不要改變,需要改變的是指向?qū)ο蟮木浔?/p>

缺點(diǎn):通過(guò)句柄這個(gè)間接訪問(wèn)對(duì)象開銷要高一些。

直接指針:訪問(wèn)的速度快于句柄,對(duì)象地址發(fā)生改變時(shí),引用也要發(fā)生改變。

總結(jié)

以上是生活随笔為你收集整理的Java知识总结(五)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

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