查看原文
其他

面试官:什么是字节码?它最大的优势是什么?

田老师 Java后端技术全栈 2021-08-29

关注Java后端技术全栈

回复“面试”获取全套面试资料

什么是字节码?

这个问题,面试官可以衍生提问,Java 是编译执行的语言,还是解释执行的语言。

Java 中引入了虚拟机的概念,即在机器和编译程序之间加入了一层抽象的虚拟的机器。这台虚拟的机器在任何平台上都提供给编译程序一个的共同的接口。

编译程序只需要面向虚拟机,生成虚拟机能够理解的代码,然后由解释器来将虚拟机代码转换为特定系统的机器码执行。在 Java 中,这种供虚拟机理解的代码叫做字节码(即扩展名为 .class 的文件),它不面向任何特定的处理器,只面向虚拟机。

随便找一个项目汇总的.class文件,然后使用16进制的方法查看:

0000000: cafe babe 0000 0034 0061 0a00 1600 4709  .......4.a....G.
00000100005 0048 0900 0500 4909 0005 0040700  ...H....I....J..
00000204b0a 0005 0040a00 0500 4d0a 0016 004e  K....L....M....N
00000300a00 0500 4f0a 0005 0050 0a00 1600 5107  ....O....P....Q.
00000400052 0a00 0c00 4708 0053 0a00 0c00 540a  .R....G..S....T.
00000500000055 0800 5608 0057 0a00 0c00 5808  ...U..V..W....X.
00000600059 0a00 0c00 5a07 0050700 5c01 0005  .Y....Z..[..\...
00000707461 6749 6401 0013 4c6a 6176 612f 6c61  tagId...Ljava/la
00000806e67 2f49 6e74 6567 6572 3b01 0007 7461  ng/Integer;...ta
0000090674616d 6501 0012 4c6a 6176 612f 6c61  gName...Ljava/la
00000a0: 6e67 2f53 7472 6966730100 0574 6f74  ng/String;...tot
00000b0: 6160100 0149 0100 0636966974 3e01  al...I...<init>.
00000c0: 0003 2829 5601 0004 436f 6465 0100 0f4c  ..()V...Code...L00000d0: 696654756d 6265 7254 6162 6c65 0100  ineNumberTable..
00000e01246f63 6165661 7269 6162 6c65 5461  .LocalVariableTa
00000f0: 6266501 0004 7468 6973 0100 1f4c 636f  ble...this...Lco
00001006d2f 6a61 7661 2f74 6961 6e2f 6266f67  m/java/tian/blog
00001102f65 6e74 6974 792f 5461 6730100 0867  /entity/Tag;...g
00001206574 5461 6749 6401 0015 2829 4c6a 6176  etTagId...()Ljav
0000130612f 6c61 6e67 2f49 6e74 6567 6572 3b01  a/lang/Integer;.00001400006765 7454 6167 4e61 6d65 0100 1428  ..getTagName...(00001502946a61 7661 2f6c 616672f 5374 7269  )Ljava/lang/Stri0000160: 6e67 3b01 0008 6765 7454 6f74 6160100  ng;...getTotal..00001700328 2949 0100 0873 6574 5461 6749 6401  .()I...setTagId.00001800016 2846a61 7661 2f6c 616672f 496e  ..(Ljava/lang/In
00001907465 6765 7232956 0100 104d 6574 686f  teger;)V...Metho
00001a0: 6450 6172 616d 6574 6572 7301 0007365  dParameters...se
00001b0: 7454 6167 4e61 6d65 0100 1528 4c6a 6176  tTagName...(Ljav00001c0: 612f 6c61 6e67 2f53 7472 6966732956  a/lang/String;)V
00001d0: 0100 0873 6574 546f 7461 6c01 0004 2849  ...setTotal...(I
00001e02956 0100 0665 7175 6167301 0015 284c  )V...equals...(L00001f0: 6a61 7661 2f6c 616672f 4f62 6a65 6374  java/lang/Object
00002003b29 5a01 0001 6f01 0012 4c6a 6176 612f  ;)Z...o...Ljava/
00002106c61 6e67 2f4f 6266563 7430100 056f  lang/Object;...o
00002207468 6572 0100 0a74 6869 7324 7461 6749  ther...this$tagI
00002306401 0006f74 6865 7224 7461 6749 6401  d...other$tagId.
00002400007468 6973 2474 6167 4e61 6d65 0100  ..this$tagName..
00002500d6f 7468 6572 2474 6167 4e61 6d65 0100  .other$tagName..
00002600d53 7461 6364d61 7054 6162 6c65 0700  .StackMapTable..
00002704b07 0050100 0863 6164571 7561 6c01  K..[...canEqual.
00002800008 6861 7368 436f 6465 0100 0550 5249  ..hashCode...PRI
00002904d45 0100 0672 6573 7567401 0006 2474  ME...result...$t
00002a0: 6167 4964 0100 0824 7461 674616d 6501  agId...$tagName.
00002b0: 0008 746f 5374 7269 6e67 0100 0a53 6f75  ..toString...Sou
00002c0: 7263 6546 6966501 0008 5461 6726a61  rceFile...Tag.ja
00002d0: 7661 0c00 1e00 1f0c 0018 0019 0c00 1a00  va..............
00002e01b0c 001001d 0100 1d63 6f6d 2f6a 6176  .........com/jav
00002f0: 612f 7469 6162f62 6c6f 672f 6567469  a/tian/blog/enti
00003007479 2f54 6167 0c00 3e00 3300025 0026  ty/Tag..>.3..%.&
00003100c00 3200 3300027 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开头的字节码了。

另外一种方式查看字节码的方式:xxd Tag.class Tag.txt和上面一样。

二进制与16进制转换还有其他一些方式,如下:

以十六进制格式输出:
od [选项] 文件
od -d 文件  十进制输出
-o 文件  八进制输出
-x 文件  十六进制输出
xxd 文件  输出十六进制

在vi命令状态下:
:%!xxd   :%!od    将当前文本转化为16进制格式
:%!xxd -c 12 每行显示12个字节
:%!xxd -r    将当前文本转化回文本格式

上面的字节码看起来是不是很无语,很多人是对其很厌烦。其实也没那么难的。

每一种平台的解释器是不同的,但是实现的虚拟机是相同的。Java 源程序经过编译器编译后变成字节码,字节码由虚拟机解释执行,虚拟机将每一条要执行的字节码送给解释器,解释器将其翻译成特定机器上的机器码,然后在特定的机器上运行。这也就是解释了 Java 的编译与解释并存的特点

Java 源代码
=> 编译器 => JVM 可执行的 Java 字节码(即虚拟指令)
=> JVM => JVM 中解释器 => 机器可执行的二进制机器码 => 程序运行
采用字节码的好处?

Java 语言通过字节码的方式,在一定程度上解决了传统解释型语言执行效率低的问题,同时又保留了解释型语言可移植的特点。所以 Java 程序运行时比较高效,而且,由于字节码并不专对一种特定的机器,因此,Java程序无须重新编译便可在多种不同的计算机上运行。

解释型语言:解释型语言,是在运行的时候将程序翻译成机器语言。解释型语言的程序不需要在运行前编译,在运行程序的时候才翻译,专门的解释器负责在每个语句执行的时候解释程序代码。这样解释型语言每执行一次就要翻译一次,效率比较低。——百度百科

例如:Python、PHP 。


推荐阅读

【原创】Spring Boot终极篇《上》

【原创】Spring Boot终极篇《下》

笔试题:了解穷举算法吗?如何用代码实现

    : . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

    您可能也对以下帖子感兴趣

    文章有问题?点此查看未经处理的缓存