回復(fù)“面試”獲取全套面試資料
什么是字節(jié)碼?
這個問題,,面試官可以衍生提問,,Java 是編譯執(zhí)行的語言,還是解釋執(zhí)行的語言,。
Java 中引入了虛擬機的概念,,即在機器和編譯程序之間加入了一層抽象的虛擬的機器。這臺虛擬的機器在任何平臺上都提供給編譯程序一個的共同的接口。
編譯程序只需要面向虛擬機,,生成虛擬機能夠理解的代碼,,然后由解釋器來將虛擬機代碼轉(zhuǎn)換為特定系統(tǒng)的機器碼執(zhí)行。在 Java 中,,這種供虛擬機理解的代碼叫做字節(jié)碼(即擴展名為 .class
的文件),,它不面向任何特定的處理器,只面向虛擬機,。
隨便找一個項目匯總的.class文件,,然后使用16進制的方法查看:
0000000: cafe babe 0000 0034 0061 0a00 1600 4709 .......4.a....G.
0000010: 0005 0048 0900 0500 4909 0005 004a 0700 ...H....I....J..
0000020: 4b0a 0005 004c 0a00 0500 4d0a 0016 004e K....L....M....N
0000030: 0a00 0500 4f0a 0005 0050 0a00 1600 5107 ....O....P....Q.
0000040: 0052 0a00 0c00 4708 0053 0a00 0c00 540a .R....G..S....T.
0000050: 000c 0055 0800 5608 0057 0a00 0c00 5808 ...U..V..W....X.
0000060: 0059 0a00 0c00 5a07 005b 0700 5c01 0005 .Y....Z..[..\...
0000070: 7461 6749 6401 0013 4c6a 6176 612f 6c61 tagId...Ljava/la
0000080: 6e67 2f49 6e74 6567 6572 3b01 0007 7461 ng/Integer;...ta
0000090: 674e 616d 6501 0012 4c6a 6176 612f 6c61 gName...Ljava/la
00000a0: 6e67 2f53 7472 696e 673b 0100 0574 6f74 ng/String;...tot
00000b0: 616c 0100 0149 0100 063c 696e 6974 3e01 al...I...<init>.
00000c0: 0003 2829 5601 0004 436f 6465 0100 0f4c ..()V...Code...L00000d0: 696e 654e 756d 6265 7254 6162 6c65 0100 ineNumberTable..
00000e0: 124c 6f63 616c 5661 7269 6162 6c65 5461 .LocalVariableTa
00000f0: 626c 6501 0004 7468 6973 0100 1f4c 636f ble...this...Lco
0000100: 6d2f 6a61 7661 2f74 6961 6e2f 626c 6f67 m/java/tian/blog
0000110: 2f65 6e74 6974 792f 5461 673b 0100 0867 /entity/Tag;...g
0000120: 6574 5461 6749 6401 0015 2829 4c6a 6176 etTagId...()Ljav
0000130: 612f 6c61 6e67 2f49 6e74 6567 6572 3b01 a/lang/Integer;.0000140: 000a 6765 7454 6167 4e61 6d65 0100 1428 ..getTagName...(0000150: 294c 6a61 7661 2f6c 616e 672f 5374 7269 )Ljava/lang/Stri0000160: 6e67 3b01 0008 6765 7454 6f74 616c 0100 ng;...getTotal..0000170: 0328 2949 0100 0873 6574 5461 6749 6401 .()I...setTagId.0000180: 0016 284c 6a61 7661 2f6c 616e 672f 496e ..(Ljava/lang/In
0000190: 7465 6765 723b 2956 0100 104d 6574 686f teger;)V...Metho
00001a0: 6450 6172 616d 6574 6572 7301 000a 7365 dParameters...se
00001b0: 7454 6167 4e61 6d65 0100 1528 4c6a 6176 tTagName...(Ljav00001c0: 612f 6c61 6e67 2f53 7472 696e 673b 2956 a/lang/String;)V
00001d0: 0100 0873 6574 546f 7461 6c01 0004 2849 ...setTotal...(I
00001e0: 2956 0100 0665 7175 616c 7301 0015 284c )V...equals...(L00001f0: 6a61 7661 2f6c 616e 672f 4f62 6a65 6374 java/lang/Object
0000200: 3b29 5a01 0001 6f01 0012 4c6a 6176 612f ;)Z...o...Ljava/
0000210: 6c61 6e67 2f4f 626a 6563 743b 0100 056f lang/Object;...o
0000220: 7468 6572 0100 0a74 6869 7324 7461 6749 ther...this$tagI
0000230: 6401 000b 6f74 6865 7224 7461 6749 6401 d...other$tagId.
0000240: 000c 7468 6973 2474 6167 4e61 6d65 0100 ..this$tagName..
0000250: 0d6f 7468 6572 2474 6167 4e61 6d65 0100 .other$tagName..
0000260: 0d53 7461 636b 4d61 7054 6162 6c65 0700 .StackMapTable..
0000270: 4b07 005b 0100 0863 616e 4571 7561 6c01 K..[...canEqual.
0000280: 0008 6861 7368 436f 6465 0100 0550 5249 ..hashCode...PRI
0000290: 4d45 0100 0672 6573 756c 7401 0006 2474 ME...result...$t
00002a0: 6167 4964 0100 0824 7461 674e 616d 6501 agId...$tagName.
00002b0: 0008 746f 5374 7269 6e67 0100 0a53 6f75 ..toString...Sou
00002c0: 7263 6546 696c 6501 0008 5461 672e 6a61 rceFile...Tag.ja
00002d0: 7661 0c00 1e00 1f0c 0018 0019 0c00 1a00 va..............
00002e0: 1b0c 001c 001d 0100 1d63 6f6d 2f6a 6176 .........com/jav
00002f0: 612f 7469 616e 2f62 6c6f 672f 656e 7469 a/tian/blog/enti
0000300: 7479 2f54 6167 0c00 3e00 330c 0025 0026 ty/Tag..>.3..%.&
0000310: 0c00 3200 330c 0027 0028 0c00 2900 2a0c ..2.3..'.(..).*.
0000320: 003f 002a 0100 176a 6176 612f 6c61 6e67 .?.*...java/lang
0000330: 2f53 7472 696e 6742 7569 6c64 6572 0100 /StringBuilder..
0000340: 0a54 6167 2874 6167 4964 3d0c 005d 005e .Tag(tagId=..].^
0000350: 0c00 5d00 5f01 000a 2c20 7461 674e 616d ..]._..., tagNam
0000360: 653d 0100 082c 2074 6f74 616c 3d0c 005d e=..., total=..]
25 lines filtered
查看方式是先使用vim將.class文件打開,然后輸入:%!xxd
然后就可以看到cafe babe
開頭的字節(jié)碼了,。
另外一種方式查看字節(jié)碼的方式:xxd Tag.class Tag.txt
和上面一樣,。
二進制與16進制轉(zhuǎn)換還有其他一些方式,如下:
以十六進制格式輸出:
od [選項] 文件
od -d 文件 十進制輸出
-o 文件 八進制輸出
-x 文件 十六進制輸出
xxd 文件 輸出十六進制
在vi命令狀態(tài)下:
:%!xxd :%!od 將當(dāng)前文本轉(zhuǎn)化為16進制格式
:%!xxd -c 12 每行顯示12個字節(jié)
:%!xxd -r 將當(dāng)前文本轉(zhuǎn)化回文本格式
上面的字節(jié)碼看起來是不是很無語,,很多人是對其很厭煩,。其實也沒那么難的。
每一種平臺的解釋器是不同的,,但是實現(xiàn)的虛擬機是相同的,。Java 源程序經(jīng)過編譯器編譯后變成字節(jié)碼,字節(jié)碼由虛擬機解釋執(zhí)行,,虛擬機將每一條要執(zhí)行的字節(jié)碼送給解釋器,,解釋器將其翻譯成特定機器上的機器碼,然后在特定的機器上運行,。這也就是解釋了 Java 的編譯與解釋并存的特點,。
Java 源代碼
=> 編譯器 => JVM 可執(zhí)行的 Java 字節(jié)碼(即虛擬指令)
=> JVM => JVM 中解釋器 => 機器可執(zhí)行的二進制機器碼 => 程序運行
采用字節(jié)碼的好處?
Java 語言通過字節(jié)碼的方式,,在一定程度上解決了傳統(tǒng)解釋型語言執(zhí)行效率低的問題,,同時又保留了解釋型語言可移植的特點。所以 Java 程序運行時比較高效,,而且,,由于字節(jié)碼并不專對一種特定的機器,因此,,Java程序無須重新編譯便可在多種不同的計算機上運行,。
解釋型語言:解釋型語言,是在運行的時候?qū)⒊绦蚍g成機器語言,。解釋型語言的程序不需要在運行前編譯,,在運行程序的時候才翻譯,專門的解釋器負責(zé)在每個語句執(zhí)行的時候解釋程序代碼,。這樣解釋型語言每執(zhí)行一次就要翻譯一次,,效率比較低,。——百度百科
例如:Python,、PHP ,。