中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java類文件的知識點有哪些

發布時間:2022-03-17 15:49:52 來源:億速云 閱讀:267 作者:iii 欄目:大數據

今天小編給大家分享一下java類文件的知識點有哪些的相關知識點,內容詳細,邏輯清晰,相信大部分人都還太了解這方面的知識,所以分享這篇文章給大家參考一下,希望大家閱讀完這篇文章后有所收獲,下面我們一起來了解一下吧。

Class文件格式采用一種類似于C語言結構體的偽結構來存儲數據,這種偽結構中只有兩種數據類型:“無符號數”和“表”。

·無符號數屬于基本的數據類型,以u1、u2、u4、u8來分別代表1個字節、2個字節、4個字節和8個字節的無符號數,無符號數可以用來描述數字、索引引用、數量值或者按照UTF-8編碼構成字符串值。

·表是由多個無符號數或者其他表作為數據項構成的復合數據類型,為了便于區分,所有表的命名都習慣性以“_info”結尾。表用于描述有層次關系的復合結構的數據,整個Class文件本質上也可以視作是一張表

java類文件的知識點有哪些

每個Class文件的頭4個字節被稱為魔數(Magic Number),它的唯一作用是確定這個文件是否為一個能被虛擬機接受的Class文件。不僅是Class文件,很多文件格式標準中都有使用魔數來進行身份識別的習慣,譬如圖片格式,如GIF或者JPEG等在文件頭中都存有魔數。

Class文件的魔數取得很有“浪漫氣息”,值為0xCAFEBABE(咖啡寶貝?)

緊接著魔數的4個字節存儲的是Class文件的版本號:第5和第6個字節是次版本號(MinorVersion),第7和第8個字節是主版本號(Major Version)。Java的版本號是從45開始的,JDK 1.1之后的每個JDK大版本發布主版本號向上加1(JDK 1.0~1.1使用了45.0~45.3的版本號),高版本的JDK能向下兼容以前版本的Class文件,但不能運行以后版本的Class文件,

常量池

緊接著主、次版本號之后的是常量池入口,常量池可以比喻為Class文件里的資源倉庫,它是Class文件結構中與其他項目關聯最多的數據,通常也是占用Class文件空間最大的數據項目之一,另外,它還是在Class文件中第一個出現的表類型數據項目。

常量池中主要存放兩大類常量:字面量(Literal)和符號引用(Symbolic References)。字面量比較接近于Java語言層面的常量概念,如文本字符串、被聲明為final的常量值等。而符號引用則屬于編譯原理方面的概念,主要包括下面幾類常量:

·被模塊導出或者開放的包(Package)

·類和接口的全限定名(Fully Qualified Name)

·字段的名稱和描述符(Descriptor)

·方法的名稱和描述符

·方法句柄和方法類型(Method Handle、Method Type、Invoke Dynamic)

·動態調用點和動態常量(Dynamically-Computed Call Site、Dynamically-Computed Constant)

Java代碼在進行Javac編譯的時候,并不像C和C++那樣有“連接”這一步驟,而是在虛擬機加載Class文件的時候進行動態連接(具體見第7章)。也就是說,在Class文件中不會保存各個方法、字段最終在內存中的布局信息,這些字段、方法的符號引用不經過虛擬機在運行期轉換的話是無法得到真正的內存入口地址,也就無法直接被虛擬機使用的。當虛擬機做類加載時,將會從常量池獲得對應的符號引用,再在類創建時或運行時解析、翻譯到具體的內存地址之中。

常量池中每一項常量都是一個表,最初常量表中共有11種結構各不相同的表結構數據,后來為了更好地支持動態語言調用,額外增加了4種動態語言相關的常量 [1] ,為了支持Java模塊化系統(Jigsaw),又加入了CONSTANT_Module_info和CONSTANT_Package_info兩個常量,所以截至JDK13,常量表中分別有17種不同類型的常量。

java類文件的知識點有哪些

順便提一下,由于Class文件中方法、字段等都需要引用CONSTANT_Utf8_info型常量來描述名稱,所以CONSTANT_Utf8_info型常量的最大長度也就是Java中方法、字段名的最大長度。而這里的最大長度就是length的最大值,既u2類型能表達的最大值65535。所以Java程序中如果定義了超過64KB英文字符的變量或方法名,即使規則和全部字符都是合法的,也會無法編譯。

Classfile /D:/BaiduYunDownload/geekbang-lessons/thinking-in-spring/validation/target/classes/org/geekbang/thinking/in/spring/validation/TestClass.class

  Last modified 2020-6-25; size 439 bytes

  MD5 checksum 18760ee8065f9fb68d4dab7bd7450c4c

  Compiled from "TestClass.java"

public class org.geekbang.thinking.in.spring.validation.TestClass

  minor version: 0

  major version: 52

  flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

   #1 = Methodref          #4.#18         // java/lang/Object."<init>":()V

   #2 = Fieldref           #3.#19         // org/geekbang/thinking/in/spring/validation/TestClass.m:I

   #3 = Class              #20            // org/geekbang/thinking/in/spring/validation/TestClass

   #4 = Class              #21            // java/lang/Object

   #5 = Utf8               m

   #6 = Utf8               I

   #7 = Utf8               <init>

   #8 = Utf8               ()V

   #9 = Utf8               Code

  #10 = Utf8               LineNumberTable

  #11 = Utf8               LocalVariableTable

  #12 = Utf8               this

  #13 = Utf8               Lorg/geekbang/thinking/in/spring/validation/TestClass;

  #14 = Utf8               inc

  #15 = Utf8               ()I

  #16 = Utf8               SourceFile

  #17 = Utf8               TestClass.java

  #18 = NameAndType        #7:#8          // "<init>":()V

  #19 = NameAndType        #5:#6          // m:I

  #20 = Utf8               org/geekbang/thinking/in/spring/validation/TestClass

  #21 = Utf8               java/lang/Object

{

  public org.geekbang.thinking.in.spring.validation.TestClass();

    descriptor: ()V

    flags: ACC_PUBLIC

    Code:

      stack=1, locals=1, args_size=1

         0: aload_0

         1: invokespecial #1                  // Method java/lang/Object."<init>":()V

         4: return

      LineNumberTable:

        line 3: 0

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0       5     0  this   Lorg/geekbang/thinking/in/spring/validation/TestClass;

  public int inc();

    descriptor: ()I

    flags: ACC_PUBLIC

    Code:

      stack=2, locals=1, args_size=1

         0: aload_0

         1: getfield      #2                  // Field m:I

         4: iconst_1

         5: iadd

         6: ireturn

      LineNumberTable:

        line 7: 0

      LocalVariableTable:

        Start  Length  Slot  Name   Signature

            0       7     0  this   Lorg/geekbang/thinking/in/spring/validation/TestClass;

}

SourceFile: "TestClass.java"

在常量池結束之后,緊接著的2個字節代表訪問標志(access_flags),這個標志用于識別一些類或者接口層次的訪問信息,包括:這個Class是類還是接口;是否定義為public類型;是否定義為abstract類型;如果是類的話,是否被聲明為final;

類索引、父類索引和接口索引集合都按順序排列在訪問標志之后,類索引和父類索引用兩個u2類型的索引值表示,它們各自指向一個類型為CONSTANT_Class_info的類描述符常量,通過CONSTANT_Class_info類型的常量中的索引值可以找到定義在CONSTANT_Utf8_info類型的常量中的全限定名字符串。

直到JDK 8中Lambda表達式和接口默認方法的出現,InvokeDynamic指令才算在Java語言生成的Class文件中有了用武之地

所以JDK 8中新增的這個屬性,使得編譯器可以

(編譯時加上-parameters參數)將方法名稱也寫進Class文件中,而且MethodParameters是方法表的屬

性,與Code屬性平級的,可以運行時通過反射API獲取。

·將一個局部變量加載到操作棧:iload

·將一個數值從操作數棧存儲到局部變量表:istore

·將一個常量加載到操作數棧:bipush

iload_<n>,它代表了iload_0、iload_1、iload_2和iload_3這幾條指令

·加法指令:iadd、ladd、fadd、dadd

·減法指令:isub、lsub、fsub、dsub

·乘法指令:imul、lmul、fmul、dmul

·除法指令:idiv、ldiv、fdiv、ddiv

·求余指令:irem、lrem、frem、drem

·取反指令:ineg、lneg、fneg、dneg

·位移指令:ishl、ishr、iushr、lshl、lshr、lushr

·按位或指令:ior、lor

·按位與指令:iand、land

·按位異或指令:ixor、lxor

·局部變量自增指令:iinc

·比較指令:dcmpg、dcmpl、fcmpg、fcmpl、lcmp

JDK  1.0.2時改動過invokespecial指令的語義,JDK 7增加了invokedynamic指令,禁止了ret和jsr指令。

類的生命周期

加載-> 連接(驗證,準備,解析)->初始化->使用->卸載。

加載、驗證、準備、初始化和卸載這五個階段的順序是確定的,類型的加載過程必須按照這種順序按部就班地開始,而解析階段則不一定:它在某些情況下可以在初始化階段之后再開始,這是為了支持Java語言的運行時綁定特性(也稱為動態綁定或晚期綁定)。

public static final int value = 123;

編譯時Javac將會為value生成ConstantValue屬性,在準備階段虛擬機就會根據Con-stantValue的設置將value賦值為123。

雙親委派模型的工作過程是:如果一個類加載器收到了類加載的請求,它首先不會自己去嘗試加載這個類,而是把這個請求委派給父類加載器去完成,每一個層次的類加載器都是如此,因此所有的加載請求最終都應該傳送到最頂層的啟動類加載器中,只有當父加載器反饋自己無法完成這個加載請求(它的搜索范圍中沒有找到所需的類)時,子加載器才會嘗試自己去完成加載

首先,是擴展類加載器(Extension Class Loader)被平臺類加載器(Platform Class Loader)取代。這其實是一個很順理成章的變動,既然整個JDK都基于模塊化進行構建(原來的rt.jar和tools.jar被拆分成數十個JMOD文件),其中的Java類庫就已天然地滿足了可擴展的需求,那自然無須再保留<JAVA_HOME>\lib\ext目錄,此前使用這個目錄或者java.ext.dirs系統變量來擴展JDK功能的機制已經沒有繼續存在的價值了,用來加載這部分類庫的擴展類加載器也完成了它的歷史使命。

所有依賴靜態類型來決定方法執行版本的分派動作,都稱為靜態分派。靜態分派的最典型應用表現就是方法重載。靜態分派發生在編譯階段,因此確定靜態分派的動作實際上不是由虛擬機來執行的,這點也是為何一些資料選擇把它歸入“解析”而不是“分派”的原因。

在Java虛擬機支持以下5條方法調用字節碼指令,分別是:

·invokestatic。用于調用靜態方法。

·invokespecial。用于調用實例構造器<init>()方法、私有方法和父類中的方法。

·invokevirtual。用于調用所有的虛方法。

·invokeinterface。用于調用接口方法,會在運行時再確定一個實現該接口的對象。

·invokedynamic。先在運行時動態解析出調用點限定符所引用的方法,然后再執行該方法。前面4條調用指令,分派邏輯都固化在Java虛擬機內部,而invokedynamic指令的分派邏輯是由用戶設定的引導方法來決定的。

只要能被invokestatic和invokespecial指令調用的方法,都可以在解析階段中確定唯一的調用版本,Java語言里符合這個條件的方法共有靜態方法、私有方法、實例構造器、父類方法4種,再加上被final修飾的方法(盡管它使用invokevirtual指令調用),這5種方法調用會在類加載的時候就可以把符號引

用解析為該方法的直接引用。這些方法統稱為“非虛方法”(Non-Virtual Method),與之相反,其他方法就被稱為“虛方法”(Virtual Method)。

解析調用一定是個靜態的過程,在編譯期間就完全確定,在類加載的解析階段就會把涉及的符號引用全部轉變為明確的直接引用,不必延遲到運行期再去完成。而另一種主要的方法調用形式:分派(Dispatch)調用則要復雜許多,它可能是靜態的也可能是動態的,按照分派依據的宗量數可分為單分派和多分派 [1] 。這兩類分派方式兩兩組合就構成了靜態單分派、靜態多分派、動態單分派、動態多分派4種分派組合情況,下面我們來看看虛擬機中的方法分派是如何進行的。

代碼中故意定義了兩個靜態類型相同,而實際類型不同的變量,但虛擬機(或者準確地說是編譯器)在重載時是通過參數的靜態類型而不是實際類型作為

判定依據的。由于靜態類型在編譯期可知,所以在編譯階段,Javac編譯器就根據參數的靜態類型決定了會使用哪個重載版本,因此選擇了sayHello(Human)作為調用目標,并把這個方法的符號引用寫到main()方法里的兩條invokevirtual指令的參數中。

所有依賴靜態類型來決定方法執行版本的分派動作,都稱為靜態分派。靜態分派的最典型應用表現就是方法重載。靜態分派發生在編譯階段,因此確定靜態分派的動作實際上不是由虛擬機來執行的,這點也是為何一些資料選擇把它歸入“解析”而不是“分派”的原因。

可見變長參數的重載優先級是最低的。字段永遠不參與多態,哪個類的方法訪問某個名字的字段時,該名字指的就是這個類能看到的那個字段。

重點

正是因為invokevirtual指令執行的第一步就是在運行期確定接收者的實際類型,所以兩次調用中的invokevirtual指令并不是把常量池中方法的符號引用解析到直接引用上就結束了,還會根據方法接收者的實際類型來選擇方法版本,這個過程就是Java語言中方法重寫的本質。我們把這種在運行期根據實際類型確定方法執行版本的分派過程稱為動態分派。多態性的根源在于虛方法調用指令invokevirtual的執行邏輯,那自然我們得出的結論就只會對方法有效,對字段是無效的,因為字段不使用這條指令。

Java語言是一門靜態多分派、動態單分派的語言。

為了程序實現方便,具有相同簽名的方法,在父類、子類的虛方法表中都應當具有一樣的索引序號,這樣當類型變換時,僅需要變更查找的虛方法表,就可以從不同的虛方法表中按索引轉換出所需的入口地址。虛方法表一般在類加載的連接階段進行初始化,準備了類的變量初始值后,虛擬機會把該類的虛方法表也一同初始化完畢。

動態類型語言支持

Java虛擬機的字節碼指令集的數量自從Sun公司的第一款Java虛擬機問世至今,二十余年間只新增過一條指令,它就是隨著JDK 7的發布的字節碼首位新成員——invokedynamic指令。這條新增加的指令是JDK 7的項目目標:實現動態類型語言(Dynamically Typed Language)支持而進行的改進之一,也是為JDK 8里可以順利實現Lambda表達式而做的技術儲備。

何謂動態類型語言 [1] ?動態類型語言的關鍵特征是它的類型檢查的主體過程是在運行期而不是編譯期進行的,滿足這個特征的語言有很多,常用的包括:APL、Clojure、Erlang、Groovy、javaScript、Lisp、Lua、PHP、Prolog、Python、Ruby、Smalltalk、Tcl,等等。那相對地,在編譯期就進行類型檢查過程的語言,譬如C++和Java等就是最常用的靜態類型語言。變量無類型而變量值才有類型

在Java虛擬機層面上提供動態類型的直接支持就成為Java平臺發展必須解決的問題,這便是JDK 7時JSR-292提案中invokedynamic指令以及java.lang.invoke包出現的技術背景。

JDK 7時新加入的java.lang.invoke包 [1] 是JSR 292的一個重要組成部分,這個包的主要目的是在之前單純依靠符號引用來確定調用的目標方法這條路之外,提供一種新的動態確定目標方法的機制,稱為“方法句柄”(Method Handle)。

·Reflection和MethodHandle機制本質上都是在模擬方法調用,但是Reflection是在模擬Java代碼層次的方法調用,而MethodHandle是在模擬字節碼層次的方法調用。

在Tomcat目錄結構中,可以設置3組目錄(/common/*、/server/*和/shared/*,但默認不一定是開放的,可能只有/lib/*目錄存在)用于存放Java類庫,另外還應該加上Web應用程序自身的“/WEB-INF/*”目錄,一共4組。把Java類庫放置在這4組目錄中,每一組都有獨立的含義,分別是:

·放置在/common目錄中。類庫可被Tomcat和所有的Web應用程序共同使用。

·放置在/server目錄中。類庫可被Tomcat使用,對所有的Web應用程序都不可見。

·放置在/shared目錄中。類庫可被所有的Web應用程序共同使用,但對Tomcat自己不可見。

·放置在/WebApp/WEB-INF目錄中。類庫僅僅可以被該Web應用程序使用,對Tomcat和其他Web應用程序都不可見。

為了支持這套目錄結構,并對目錄里面的類庫進行加載和隔離,Tomcat自定義了多個類加載器,這些類加載器按照經典的雙親委派模型來實現

java類文件的知識點有哪些

Common類加載器、Catalina類加載器(也稱為Server類加載器)、Shared類加載器和Webapp類加載器則是Tomcat自己定義的類加載器,它們分別加載/common/*、/server/*、/shared/*和/WebApp/WEB-INF/*中的Java類庫。其中WebApp類加載器和JSP類加載器通常還會存在多個實例,每一個Web應用程序對應一個WebApp類加載器,每一個JSP文件對應一個JasperLoader類加載器。

而JasperLoader的加載范圍僅僅是這個JSP文件所編譯出來的那一個Class文件,它存在的目的就是為了被丟棄:當服務器檢測到JSP文件被修改時,會替換掉目前的JasperLoader的實例,并通過再建立一個新的JSP類加載器來實現JSP文件的HotSwap功能。

以上就是“java類文件的知識點有哪些”這篇文章的所有內容,感謝各位的閱讀!相信大家閱讀完這篇文章都有很大的收獲,小編每天都會為大家更新不同的知識,如果還想學習更多的知識,請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

天台县| 比如县| 邢台县| 曲阜市| 玉林市| 封丘县| 武川县| 兴义市| 枞阳县| 黔西县| 正镶白旗| 深泽县| 铜川市| 上虞市| 出国| 靖宇县| 新密市| 衡南县| 丘北县| 蒲城县| 盈江县| 台中市| 乌审旗| 吉林省| 白沙| 彭阳县| 丹寨县| 雷山县| 莱州市| 开原市| 大兴区| 姚安县| 建湖县| 沧源| 宁明县| 丹阳市| 合山市| 扬州市| 贞丰县| 永嘉县| 铜川市|