javap的用途不断发展:您的Java类文件中隐藏了什么?
什么是Javap,如何使用它以及何時(shí)要反匯編類(lèi)文件?
作為Java開(kāi)發(fā)工具包(JDK)的一部分,我們可以使用許多工具,這些工具有助于更好地理解Java代碼。 這些工具之一是javap命令,它為我們提供了對(duì)Java類(lèi)文件的后臺(tái)傳遞。
在下面的文章中,我們將研究javap,了解它如何為我們提供幫助,并確切地了解如何使用它。 代碼,反匯編!
什么是javap?
javap是一個(gè)命令行工具,可分解Java類(lèi)文件:它分解了我們的類(lèi)文件,并揭示了其中的內(nèi)容。 該工具將二進(jìn)制格式的類(lèi)文件轉(zhuǎn)換為人類(lèi)可讀的代碼。 好吧,對(duì)于某些人。
javap提供了許多輸出,這些輸出根據(jù)我們感興趣的數(shù)據(jù)而有所不同。默認(rèn)情況下,javap打印每個(gè)類(lèi)的非私有成員的聲明。
至于javap中的p代表什么,所有證據(jù)都指向“打印”,因?yàn)閖avap命令會(huì)打印出類(lèi)中的字節(jié)碼。
我們可以使用javap的一種好方法是探索異常。 如果您想提高自己的知識(shí)并了解引發(fā)異常時(shí)會(huì)發(fā)生什么,請(qǐng)查看我們的文章,了解有關(guān)Java異常的令人驚訝的真相 。
在我們的類(lèi)中使用javap
既然我們知道了javap是什么,該是在我們的代碼上嘗試使用它的時(shí)候了。 我們通過(guò)鍵入命令,選擇一個(gè)選項(xiàng)并添加類(lèi)名來(lái)做到這一點(diǎn):
javap [選項(xiàng)]類(lèi)名
正如我們指出的,這些選項(xiàng)(也可以稱為標(biāo)志)將決定我們的輸出是什么。 我們可以從許多標(biāo)志中進(jìn)行選擇,包括:
- -l –輸出行和局部變量表
- -public –僅顯示公共班級(jí)和成員
- -protected –僅顯示受保護(hù)的和公開(kāi)的班級(jí)和成員
- -package –僅顯示軟件包,受保護(hù)的和公共的類(lèi)和成員
- -p –顯示所有班級(jí)和成員
- -Jflag –將標(biāo)志直接傳遞到運(yùn)行時(shí)系統(tǒng)
- -s –打印內(nèi)部類(lèi)型簽名
- -sysinfo –顯示正在處理的類(lèi)的系統(tǒng)信息(路徑,大小,日期,MD5哈希)
- -constants –顯示靜態(tài)最終常量
- -c –打印反匯編的代碼
- -verbose –打印堆棧大小,方法的局部變量和args
用javap深入字節(jié)碼
在列出了可以使用javap進(jìn)行的操作之后,現(xiàn)在該弄清楚它的實(shí)際工作方式了。 為此,我們創(chuàng)建了一個(gè)名為ExampleClass的基本類(lèi):
public class ExampleClass {private int a = 0;private int b = 0;public static void main(String[] args) {System.out.println("Hello world!");} }現(xiàn)在讓我們?cè)趈avap的幫助下更深入地研究它。 首先,我們將使用不帶任何其他標(biāo)志的javap命令來(lái)打印出非私有成員。 我們的輸出是這樣的:
$ javap ExampleClassCompiled from "ExampleClass.java" public class ExampleClass {public ExampleClass();public static void main(java.lang.String[]); }如您所見(jiàn),這是原始代碼的漂亮“普通”視圖,沒(méi)有有關(guān)私有整數(shù)和邏輯的任何信息。 這是一個(gè)好的開(kāi)始,但是如果我們想更深入地了解呢? 讓我們嘗試使用-c打印出反匯編的代碼:
$ javap -c ExampleClassCompiled from "ExampleClass.java" public class ExampleClass {public ExampleClass();Code:0: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: iconst_06: putfield #2 // Field a:I9: aload_010: iconst_011: putfield #3 // Field b:I14: returnpublic static void main(java.lang.String[]);Code:0: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #5 // String Hello world!5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: return }現(xiàn)在,我們的字節(jié)碼具有某種可讀性,可以在其中識(shí)別我們的方法,整數(shù),命令和字符串。 但是等等,還有更多。 如果我們想了解有關(guān)該課程的更多信息怎么辦? 那是我們?nèi)唛L(zhǎng)的標(biāo)志可以幫助我們的地方:
$ javap -v ExampleClassClassfile /Users/es/ExampleClass.classLast modified May 22, 2017; size 496 bytesMD5 checksum 7d29362228a3128e67b0c20c8bb54ee1Compiled from "ExampleClass.java" public class ExampleClassSourceFile: "ExampleClass.java"minor version: 0major version: 51flags: ACC_PUBLIC, ACC_SUPER Constant pool:#1 = Methodref #8.#20 // java/lang/Object."<init>":()V#2 = Fieldref #7.#21 // ExampleClass.a:I#3 = Fieldref #7.#22 // ExampleClass.b:I#4 = Fieldref #23.#24 // java/lang/System.out:Ljava/io/PrintStream;#5 = String #25 // Hello world!#6 = Methodref #26.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V#7 = Class #28 // ExampleClass#8 = Class #29 // java/lang/Object#9 = Utf8 a#10 = Utf8 I#11 = Utf8 b#12 = Utf8 <init>#13 = Utf8 ()V#14 = Utf8 Code#15 = Utf8 LineNumberTable#16 = Utf8 main#17 = Utf8 ([Ljava/lang/String;)V#18 = Utf8 SourceFile#19 = Utf8 ExampleClass.java#20 = NameAndType #12:#13 // "<init>":()V#21 = NameAndType #9:#10 // a:I#22 = NameAndType #11:#10 // b:I#23 = Class #30 // java/lang/System#24 = NameAndType #31:#32 // out:Ljava/io/PrintStream;#25 = Utf8 Hello world!#26 = Class #33 // java/io/PrintStream#27 = NameAndType #34:#35 // println:(Ljava/lang/String;)V#28 = Utf8 ExampleClass#29 = Utf8 java/lang/Object#30 = Utf8 java/lang/System#31 = Utf8 out#32 = Utf8 Ljava/io/PrintStream;#33 = Utf8 java/io/PrintStream#34 = Utf8 println#35 = Utf8 (Ljava/lang/String;)V {public ExampleClass();flags: ACC_PUBLICCode:stack=2, locals=1, args_size=10: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: iconst_06: putfield #2 // Field a:I9: aload_010: iconst_011: putfield #3 // Field b:I14: returnLineNumberTable:line 1: 0line 3: 4line 4: 9public static void main(java.lang.String[]);flags: ACC_PUBLIC, ACC_STATICCode:stack=2, locals=1, args_size=10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;3: ldc #5 // String Hello world!5: invokevirtual #6 // Method java/io/PrintStream.println:(Ljava/lang/String;)V8: returnLineNumberTable:line 7: 0line 8: 8 }很多行在我們面前展開(kāi)。 我們可以看到以下內(nèi)容:
1.元數(shù)據(jù)–此類(lèi)文件的位置,上次修改時(shí)間以及具有其唯一ID的類(lèi)哈希
2.常量池–結(jié)構(gòu)表,它引用ClassFile結(jié)構(gòu)及其子結(jié)構(gòu)中的各種常量。 它保存類(lèi),接口,類(lèi)實(shí)例,字段名稱,字符串常量或數(shù)組的符號(hào)信息。
3.字節(jié)碼–用JVM可以“讀取”的語(yǔ)言編寫(xiě)的指令集
在OverOps,我們使用javap作為研究工具來(lái)挖掘類(lèi)。 我們最近使用它來(lái)發(fā)現(xiàn)IBM J9的工作原理,為使用此JVM的開(kāi)發(fā)人員提供支持。 如果您想了解更多有關(guān)我們?nèi)绾螏椭鷪F(tuán)隊(duì)減少調(diào)試時(shí)間并知道代碼在何時(shí)何地中斷的原因, 請(qǐng)單擊此處以安排演示 。
現(xiàn)在我們知道了如何使用javap,是時(shí)候回答一個(gè)重要的問(wèn)題了:
到底有什么好處呢?
Javap很酷,特別是如果您是像我們這樣的數(shù)據(jù)迷并且想知道代碼背后發(fā)生了什么時(shí)。 但是除了不錯(cuò)的代碼探索冒險(xiǎn)外,它也非常有用。
對(duì)于原始源代碼不可用的情況,它可能會(huì)派上用場(chǎng),其中顯示了可以使用的方法。 它還可以幫助找出別人的代碼或3rd party類(lèi)中的內(nèi)容。
我們還可以將javap用作Java類(lèi)的類(lèi)驗(yàn)證器,以確保每個(gè)加載的類(lèi)文件都以適當(dāng)?shù)姆绞竭M(jìn)行結(jié)構(gòu)化。
剛開(kāi)始,javap感覺(jué)就像是一根魔杖,可以在代碼內(nèi)為我們提供所有信息,但它并不是對(duì)我們所面臨的每個(gè)問(wèn)題的完整解決方案。 它可能會(huì)幫助“逆向工程”某些代碼,但這只是一個(gè)復(fù)雜難題中的一個(gè)線索。
如果您正在尋找一種將javap字節(jié)碼輸出轉(zhuǎn)換為功能性Java代碼的方法,而不僅僅是“數(shù)據(jù)列表”,那么您將需要反編譯工具(如JD , Mocha等)的幫助。
最后的想法
盡管您不會(huì)經(jīng)常使用它,但是javap是一個(gè)有用的工具,請(qǐng)牢記。 除了這是一個(gè)很酷的“技巧”之外,它還更深入地介紹了Java代碼,向我們展示了幕后發(fā)生的事情以及JVM如何使用我們的代碼。
翻譯自: https://www.javacodegeeks.com/2017/06/javap-usage-unfolds-whats-hidden-inside-java-class-files.html
總結(jié)
以上是生活随笔為你收集整理的javap的用途不断发展:您的Java类文件中隐藏了什么?的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 梅字怎么组词 梅拼音及释义
- 下一篇: 非静态方法可以访问Java中的静态变量/