<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                **Java 為什么跨平臺** 先將java文件編譯成字節碼(.class)文件, 在所有的平臺上生成的字節碼文件都是相同的。 再使用Java虛擬機運行字節碼文件。因為不同操作系統有對應版本的jvm, 這使得同一個java代碼文件可以在不同的平臺上運行。 **.class 文件里是什么** .源代碼經過編譯器編譯之后會生成一個字節碼文件, 字節碼是一種二進制的類文件, 它的內容是JVM的指令. **JVM 的生命周期** **虛擬機的啟動** Java 虛擬機的啟動是通過引導類加載器(bootstrap class loader) 場景一個初始類(initial class) 來完成的 , 這個類是由虛擬機的具體實現指定的. **虛擬機的退出有如下幾種情況** * 某線程調用Runtime類或System類的exit方法, 或Runtime類的halt方法,并且Java安全管理器也允許這次exit或halt操作。 * 程序正常執行結束 * 程序在執行過程中遇到了異常或錯誤而異常終止 * 由于操作系統出現錯誤而導致Java虛擬機進程終止 **簡述 HotSpot 虛擬機** * SUN的JDK版本從1.3.1開始運用HotSpot虛擬機, 2006年底開源,主要使用C++實現, JNI接口部·分用C實現, 用來**替換舊的解釋型虛擬機 classic。** * HotSpot是較新的Java虛擬機, 使用JIT(Just in Time)編譯器,可以大大提高Java運行的性能。 * Java原先是把源代碼編譯為字節碼在虛擬機執行,這樣執行速度較慢。而HotSpot將常用的部分代碼**編譯為本地(原生, native)代碼**,這樣顯著**提高了性能**。 * HotSpot JVM參數可以分為規則參數(standard options)和非規則參數(non-standard options),規則參數相對穩定,在JDK未來的版本里不會有太大的改動。非規則參數則有因升級JDK而改動的可能。 **JVM 的組成? 虛擬機的體系結構?** 1. 類加載器 2. 運行時數據區 3. 執行引擎 ![](https://img.kancloud.cn/88/2e/882eb2e4b529aa785962f9e2888253f9_992x849.png) 這個架構可以分成三層看: * 最上層:javac編譯器將編譯好的字節碼class文件,通過java 類裝載器執行機制,把對象或class文件存放在 jvm劃分內存區域。 * 中間層:稱為Runtime Data Area,主要是在Java代碼運行時用于存放數據的,從左至右為方法區(永久代、元數據區)、堆(共享,GC回收對象區域)、棧、程序計數器、寄存器、本地方法棧(私有)。 * 最下層:解釋器、JIT(just in time)編譯器和 GC(Garbage Collection,垃圾回收器) **什么是字節碼的指令** Java虛擬機的指令由一個字節長度的、代表著某種特定操作含義的操作碼(opcode)以及跟隨其后的零至多個代表此操作所需參數的操作數(operand)所構成。虛擬機中許多指令并不包含操作數,只有一個操作碼。 **int i = 1; i = i++; i = ?** **字節碼在賦值過程會在 操作數棧 存一份 i=1, 而自增只是在局部變量表自增, 不會影響操作數棧的數據, 后面從操作數棧讀取 i 覆蓋了局部變量表的數據** 變形 int i = 2; i \*= i++; // 4 和上面原因一樣 int i =10; i = i + (i++) + (++i); // 32 // 第一個括號先讀取出 10 , 然后自增了1, 就是 10 +10 但是這時候 i = 11了, 第二個括號在計算的時候是 11 進行自增成 12 10 + 10 + 12 **包裝類的緩存** Integer -128 到 127 之內(包含這倆) 都是用的同一個對象, 不在這個區間就是 new 了個新對象 125 == 125, 255 != 255 valueOf 方法里判斷的 Boolean 有倆常量 true 和 false valueOf 方法里判斷的 ![](https://img.kancloud.cn/19/c7/19c798ceeb166f39e01a9577c3916ceb_688x343.png) **字符串** // string聲明的字面量數據都放在字符串常量池中 // jdk 6中宇符串常量池存放在方法區(即永久代中) // jdk 7及以后字符串常量池存放在堆空間 ``` String str = new String("hello") + new String("world"); String str1 = "helloworld"; System.out.println(str == str1); // false, str 實際在字節碼中 是使用 StringBuilder 拼接的, 最后通過 StringBuilder 的 toString() 方法返回了一個 new String() ``` ``` String str = new String("hello") + new String("world"); str.intern(); // 返回 String str1 = "helloworld"; System.out.println(str == str1); // 1.6 是false, 1.7 是ture, intern 方法之后會返回常量池中這個值(沒有會創建) // 1.6 時 常量池在方法區和 intern 返回的不在一起(堆空間), 所以是倆變量 // 1.7 時 常量池也在堆空間, 這時候如果先 intern 就會把堆空間的引用地址 // 賦值給常量池, 這時候就用到同一個了. 如果后 intern 就直接從常量池中取值返回 System.out.println(str.intern() == str1); // true ``` // new StringBuilder("hellonihao").toString() 倆字符串, // 一個 "hellonihao" 常量, 一個 new String 的 "hellonihao" ``` // 先 有常量, 后 intern() 則這個 toString() 后的值和 intern 的不相等 // new StringBuilder("hellonihao").toString() 倆字符串, // 一個 "hellonihao" 常量, 一個 new String 的 "hellonihao" String str2 = new StringBuilder("hellonihao").toString(); // false System.out.println(str2 == str2.intern()); // jdk 中 本身已經有了 "Java(TM) SE Runtime Environment" 常量 // 組成 新字符串時, 原來的詞組組合在一起的字符串出現過常量, 不是首次, // StringBuilder.toString() 會重新生成一個, 不是把常量的引用拿過來用 String str2 = new StringBuilder("Java(TM) SE ") .append("Runtime Environment").toString(); // false System.out.println(str2.intern() == str2); String ss = "Java(TM) SE Runtime Environment"; // true System.out.println(str2.intern() == ss); ``` **輸出的結果是** ![](https://img.kancloud.cn/a2/58/a258d42a3037760e17cb7293def4793b_949x549.png) Father f = new Son(); System.out.println(f.x); 執行過程是 1\. 子類構造器會**先調用父類構造器**, 在這里, 父類構造器里的this 指向的是 子類, **調用的也就是子類 print 方法**, 因為子類已經**重寫了print**, 直接就執行子類的print方法, 但是這時候子類的 **x 還沒有賦值 = 30,**所以輸出 Son.x = 0。 2\. 執行完父類構造器再執行子類構造器,這時候**再調用子類的print x 已經是30了**, 所以輸出 Son.x = 30。 3\. **f.x 是調用的 父類 x 變量**, 所以輸出 20,父類的 x 在父類構造器中修改為 20了,父類 = new 子類 多態時, 父類是調用不了子類的變量的, 如果子類還定義了個 a 變量, 這時候是沒法 f.a 的 **字節碼** **字節碼(.class) 文件結構** * 魔數 (用來標識文件類型的) * class文件版本 (jdk的版本信息) * 常量池計數器 和 常量池表數據 * 訪問標識(或標志) (public final 等等信息 ) * 類索引、父類索引、接口索引集合 (繼承那個類, 實現哪些接口) * 字段表集合 * 方法表集合 * 屬性表集合 ![](https://img.kancloud.cn/d9/bb/d9bbcf1adcc38fff62c60a81ef45997e_1500x641.png) **字節碼指令分類** * 加載與存儲指令 * 算術指令 * 類型轉換指令 * 對象的創建與訪問指令 * 方法調用與返回指令 * 操作數棧管理指令 * 控制轉移指令 * 異常處理指令 * 同步控制指令 **方法指令調用** ![](https://img.kancloud.cn/22/c5/22c581dcca3ff3f75b5ee9d2ba5ba5ee_673x498.png) **基本類型為什么不存到堆中而是存到棧中** 棧空間相對小, 運算速度更快, 基本類型占用空間小更適合放到棧中
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看