【Java基本功】離開IDE,使用javac和Java構建項目

  • 2019 年 10 月 7 日
  • 筆記

前言:本文教你怎麼用javac和java命令,講解了classpath的原理,以及如何利用腳本(shell或bat)進行項目部署,離開ide,還原最本質的Java編譯運行過程,並用簡單的實例展示這些用法。

IDE是把雙刃劍,它可以什麼都幫你做了,你只要敲幾行程式碼,點幾下滑鼠,程式就跑起來了,用起來相當方便。 你不用去關心它後面做了些什麼,執行了哪些命令,基於什麼原理。然而也是這種過分的依賴往往讓人散失了最基本的技能,當到了一個沒有IDE的地方,你便覺得無從下手,給你個程式碼都不知道怎麼去跑。好比給你瓶水,你不知道怎麼打開去喝,然後活活給渴死。 之前用慣了idea,Java文件編譯運行的命令基本忘得一乾二淨。 現在項目出了原型,放到伺服器上去測試,SSH一登陸上伺服器就傻眼了,都是命令行,以前程式圖標什麼的都成了浮雲,程式放上去了不知道怎麼去編譯運行,只能補補課了,下面做下補課筆記。 javac命令初窺

註:以下紅色標記的參數在下文中有所講解。

本部分參考https://www.cnblogs.com/xiazdong/p/3216220.html

用法: javac

其中, 可能的選項包括:

-g 生成所有調試資訊 -g:none 不生成任何調試資訊 -g:{lines,vars,source} 只生成某些調試資訊 -nowarn 不生成任何警告 -verbose 輸出有關編譯器正在執行的操作的消息 -deprecation 輸出使用已過時的 API 的源位置 -classpath <路徑> 指定查找用戶類文件和注釋處理程式的位置 -cp <路徑> 指定查找用戶類文件和注釋處理程式的位置 -sourcepath <路徑> 指定查找輸入源文件的位置 -bootclasspath <路徑> 覆蓋引導類文件的位置 -extdirs <目錄> 覆蓋所安裝擴展的位置 -endorseddirs <目錄> 覆蓋簽名的標準路徑的位置 -proc:{none,only} 控制是否執行注釋處理和/或編譯。 -processor[,,…] 要運行的注釋處理程式的名稱; 繞過默認的搜索進程 -processorpath <路徑> 指定查找注釋處理程式的位置 -d <目錄> 指定放置生成的類文件的位置 -s <目錄> 指定放置生成的源文件的位置 -implicit:{none,class} 指定是否為隱式引用文件生成類文件 -encoding <編碼> 指定源文件使用的字元編碼 -source <發行版> 提供與指定發行版的源兼容性 -target <發行版> 生成特定 VM 版本的類文件 -version 版本資訊 -help 輸出標準選項的提要 -A關鍵字[=值] 傳遞給注釋處理程式的選項 -X 輸出非標準選項的提要 -J<標記> 直接將 <標記> 傳遞給運行時系統 -Werror 出現警告時終止編譯 @<文件名> 從文件讀取選項和文件名

在詳細介紹javac命令之前,先看看這個classpath是什麼

classpath是什麼

在dos下編譯java程式,就要用到classpath這個概念,尤其是在沒有設置環境變數的時候。classpath就是存放.class等編譯後文件的路徑。

javac:如果當前你要編譯的java文件中引用了其它的類(比如說:繼承),但該引用類的.class文件不在當前目錄下,這種情況下就需要在javac命令後面加上-classpath參數,通過使用以下三種類型的方法 來指導編譯器在編譯的時候去指定的路徑下查找引用類。

(1).絕對路徑:javac -classpath c:/junit3.8.1/junit.jar Xxx.java (2).相對路徑:javac -classpath ../junit3.8.1/Junit.javr Xxx.java (3).系統變數:javac -classpath %CLASSPATH% Xxx.java (注意:%CLASSPATH%表示使用系統變數CLASSPATH的值進行查找,這裡假設Junit.jar的路徑就包含在CLASSPATH系統變數中)

IDE中的classpath

對於一個普通的Javaweb項目,一般有這樣的配置:

1 WEB-INF/classes,lib才是classpath,WEB-INF/ 是資源目錄, 客戶端不能直接訪問。 2、WEB-INF/classes目錄存放src目錄java文件編譯之後的class文件,xml、properties等資源配置文件,這是一個定位資源的入口。 3、引用classpath路徑下的文件,只需在文件名前加classpath: classpath:applicationContext-*.xml classpath:context/conf/controller.xml 4、lib和classes同屬classpath,兩者的訪問優先順序為: lib>classes。 5、classpath 和 classpath* 區別: classpath:只會到你的class路徑中查找找文件; classpath*:不僅包含class路徑,還包括jar文件中(class路徑)進行查找。

總結:

(1).何時需要使用-classpath:當你要編譯或執行的類引用了其它的類,但被引用類的.class文件不在當前目錄下時,就需要通過-classpath來引入類

(2).何時需要指定路徑:當你要編譯的類所在的目錄和你執行javac命令的目錄不是同一個目錄時,就需要指定源文件的路徑(CLASSPATH是用來指定.class路徑的,不是用來指定.java文件的路徑的)

Java項目和Java web項目的本質區別

(看清IDE及classpath本質)

現在只是說說Java Project和Web Project,那麼二者有區別么?回答:沒有!都是Java語言的應用,只是應用場合不同罷了,那麼他們的本質到底是什麼? 回答:編譯後路徑!虛擬機執行的是class文件而不是java文件,那麼我們不管是何種項目都是寫的java文件,怎麼就不一樣了呢?分成java和web兩種了呢? 從.classpath文件入手來看,這個文件在每個項目目錄下都是存在的,很少有人打開看吧,那麼我們就來一起看吧。這是一個XML文件,使用文本編輯器打開即可。 這裡展示一個web項目的.classpath

Xml程式碼

<?xml version="1.0" encoding="UTF-8"?>  <classpath>  <classpathentry kind="src" path="src"/>  <classpathentry kind="src" path="resources"/>  <classpathentry kind="src" path="test"/>  <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>  <classpathentry kind="lib" path="lib/servlet-api.jar"/>  <classpathentry kind="lib" path="webapp/WEB-INF/lib/struts2-core-2.1.8.1.jar"/>       ……  <classpathentry kind="output" path="webapp/WEB-INF/classes"/>  </classpath>

XML文檔包含一個根元素,就是classpath,類路徑,那麼這裡面包含了什麼資訊呢?子元素是classpathentry,kind屬性區別了種 類資訊,src源碼,con你看看後面的path就知道是JRE容器的資訊。lib是項目依賴的第三方類庫,output是src編譯後的位置。 既然是web項目,那麼就是WEB-INF/classes目錄,可能用MyEclipse的同學會說他們那裡是WebRoot或者是WebContext而不是webapp,有區別么?回答:完全沒有! 既然看到了編譯路徑的本來面目後,還區分什麼java項目和web項目么?回答:不區分!普通的java 項目你這樣寫就行了:,看看Eclipse是不是這樣生成的?這個問題解決了吧。 再說說webapp目錄命名的問題,這個無所謂啊,web項目是要發布到伺服器上的對吧,那麼伺服器讀取的是類文件和頁面文件吧,它不管源文件,它也無法去理解源文件。那麼webapp目錄的命名有何關係呢?只要讓伺服器找到不就行了。

Javac命令詳解

-g、-g:none、-g:{lines,vars,source}

•-g:在生成的class文件中包含所有調試資訊(行號、變數、源文件) •-g:none :在生成的class文件中不包含任何調試資訊。 這個參數在javac編譯中是看不到什麼作用的,因為調試資訊都在class文件中,而我們看不懂這個class文件。 為了看出這個參數的作用,我們在eclipse中進行實驗。在eclipse中,我們經常做的事就是「debug」,而在debug的時候,我們會 •加入「斷點」,這個是靠-g:lines起作用,如果不記錄行號,則不能加斷點。 •在「variables」窗口中查看當前的變數,如下圖所示,這是靠-g:vars起作用,否則不能查看變數資訊。 •在多個文件之間來回調用,比如 A.java的main()方法中調用了B.java的fun()函數,而我想看看程式進入fun()後的狀態,這是靠-g:source,如果沒有這個參數,則不能查看B.java的源程式碼。

-bootclasspath、-extdirs

-bootclasspath和-extdirs 幾乎不需要用的,因為他是用來改變 「引導類」和「擴展類」。 •引導類(組成Java平台的類):Javajdk1.7.025jrelibrt.jar等,用-bootclasspath設置。 •擴展類:Javajdk1.7.025jrelibext目錄中的文件,用-extdirs設置。 •用戶自定義類:用-classpath設置。 我們用-verbose編譯後出現的「類文件的搜索路徑」,就是由上面三個路徑組成,如下:

[類文件的搜索路徑: C:Javajdk1.7.0_25jrelibresources.jar,C:Javajdk1.7.0_25    jrelibrt.jar,C:Javajdk1.7.0_25jrelibsunrsasign.jar,C:Javajdk1.7.0_25j    relibjsse.jar,C:Javajdk1.7.0_25jrelibjce.jar,C:Javajdk1.7.0_25jrelib    charsets.jar,C:Javajdk1.7.0_25jrelibjfr.jar,C:Javajdk1.7.0_25jreclasses    ,C:Javajdk1.7.0_25jrelibextaccess-bridge-32.jar,C:Javajdk1.7.0_25jreli    bextdnsns.jar,C:Javajdk1.7.0_25jrelibextjaccess.jar,C:Javajdk1.7.0_25    jrelibextlocaledata.jar,C:Javajdk1.7.0_25jrelibextsunec.jar,C:Javajdk    1.7.0_25jrelibextsunjce_provider.jar,C:Javajdk1.7.0_25jrelibextsunmsca    pi.jar,C:Javajdk1.7.0_25jrelibextsunpkcs11.jar,C:Javajdk1.7.0_25jrelib  extzipfs.jar,..bin]

如果利用 -bootclasspath 重新定義: javac -bootclasspath src Xxx.java,則會出現下面錯誤:

致命錯誤: 在類路徑或引導類路徑中找不到程式包 java.lang

-sourcepath和-classpath(-cp)

•-classpath(-cp)指定你依賴的類的class文件的查找位置。在Linux中,用「:」分隔classpath,而在windows中,用「;」分隔。 •-sourcepath指定你依賴的類的java文件的查找位置。

舉個例子,

public class A  {      public static void main(String[] args) {          B b = new B();          b.print();      }  }        public class B  {      public void print()      {          System.out.println("old");      }  }

目錄結構如下:

sourcepath //此處為當前目錄

|-src      |-com        |- B.java      |- A.java    |-bin      |- B.class               //是 B.java

編譯後的類文件

如果要編譯 A.java,則必須要讓編譯器找到類B的位置,你可以指定B.class的位置,也可以是B.java的位置,也可以同時都存在。

javac -classpath bin src/A.java                            //查找到B.class    javac -sourcepath src/com src/A.java                   //查找到B.java    javac -sourcepath src/com -classpath bin src/A.java    //同時查找到B.class和B.java

如果同時找到了B.class和B.java,則: •如果B.class和B.java內容一致,則遵循B.class。 •如果B.class和B.java內容不一致,則遵循B.java,並編譯B.java。

以上規則可以通過 -verbose選項看出。

-d

•d就是 destination,用於指定.class文件的生成目錄,在eclipse中,源文件都在src中,編譯的class文件都是在bin目錄中。

這裡我用來實現一下這個功能,假設項目名稱為project,此目錄為當前目錄,且在src/com目錄中有一個Main.java文件。『

package com;  public class Main  {      public static void main(String[] args) {          System.out.println("Hello");      }  }        javac -d bin src/com/Main.java

上面的語句將Main.class生成在bin/com目錄下。

-implicit:{none,class}

•如果有文件為A.java(其中有類A),且在類A中使用了類B,類B在B.java中,則編譯A.java時,默認會自動編譯B.java,且生成B.class。 •implicit:none:不自動生成隱式引用的類文件。 •implicit:class(默認):自動生成隱式引用的類文件。

public class A  {      public static void main(String[] args) {          B b = new B();      }  }    public class B  {  }    如果使用:       javac -implicit:none A.java

則不會生成 B.class。

-source和-target

•-source:使用指定版本的JDK編譯,比如:-source 1.4表示用JDK1.4的標準編譯,如果在源文件中使用了泛型,則用JDK1.4是不能編譯通過的。 •-target:指定生成的class文件要運行在哪個JVM版本,以後實際運行的JVM版本必須要高於這個指定的版本。

javac -source 1.4 Xxx.java

javac -target 1.4 Xxx.java

-encoding

默認會使用系統環境的編碼,比如我們一般用的中文windows就是GBK編碼,所以直接javac時會用GBK編碼,而Java文件一般要使用utf-8,如果用GBK就會出現亂碼。

•指定源文件的編碼格式,如果源文件是UTF-8編碼的,而-encoding GBK,則源文件就變成了亂碼(特別是有中文時)。

javac -encoding UTF-8 Xxx.java

-verbose

輸出詳細的編譯資訊,包括:classpath、載入的類文件資訊。

比如,我寫了一個最簡單的HelloWorld程式,在命令行中輸入:

D:Java>javac -verbose -encoding UTF-8 HelloWorld01.java

輸出:

[語法分析開始時間 RegularFileObject[HelloWorld01.java]]  [語法分析已完成, 用時 21 毫秒]  [源文件的搜索路徑: .,D:大三下編譯原理cupjava-cup-11a.jar,E:javajflexlibJ           //-sourcepath  Flex.jar]  [類文件的搜索路徑: C:Javajdk1.7.0_25jrelibresources.jar,C:Javajdk1.7.0_25      //-classpath、-bootclasspath、-extdirs  省略............................................  [正在載入ZipFileIndexFileObject[C:Javajdk1.7.0_25libct.sym(META-INF/sym/rt.j  ar/java/lang/Object.class)]]  [正在載入ZipFileIndexFileObject[C:Javajdk1.7.0_25libct.sym(META-INF/sym/rt.j  ar/java/lang/String.class)]]  [正在檢查Demo]  省略............................................  [已寫入RegularFileObject[Demo.class]]  [共 447 毫秒]

編寫一個程式時,比如寫了一句:System.out.println("hello"),實際上還需要載入:Object、PrintStream、String等類文件,而上面就顯示了載入的全部類文件。

其他命令

-J <標記> •傳遞一些資訊給 Java Launcher.

javac -J-Xms48m   Xxx.java          //set the startup memory to 48M.

-@<文件名>

如果同時需要編譯數量較多的源文件(比如1000個),一個一個編譯是不現實的(當然你可以直接 javac *.java ),比較好的方法是:將你想要編譯的源文件名都寫在一個文件中(比如sourcefiles.txt),其中每行寫一個文件名,如下所示: HelloWorld01.java HelloWorld02.java HelloWorld03.java

則使用下面的命令:

javac @sourcefiles.txt

編譯這三個源文件。

使用javac構建項目

這部分參考: https://blog.csdn.net/mingover/article/details/57083176

一個簡單的javac編譯

新建兩個文件夾,src和 build src/com/yp/test/HelloWorld.java build/

├─build  └─src      └─com          └─yp              └─test                      HelloWorld.java

java文件非常簡單

package com.yp.test;  public class HelloWorld {        public static void main(String[] args) {          System.out.println("helloWorld");      }  }

編譯: javac src/com/yp/test/HelloWorld.java -d build

-d 表示編譯到 build文件夾下

查看build文件夾  ├─build  │  └─com  │      └─yp  │          └─test  │                  HelloWorld.class  │  └─src      └─com          └─yp              └─test                      HelloWorld.java

運行文件

E:codeplacen_learnjavajavacmd> java com/yp/test/HelloWorld.class 錯誤: 找不到或無法載入主類 build.com.yp.test.HelloWorld.class 運行時要指定main E:codeplacen_learnjavajavacmdbuild> java com.yp.test.HelloWorld helloWorld

如果引用到多個其他的類,應該怎麼做呢 ?

編譯 E:codeplacen_learnjavajavacmd>javac src/com/yp/test/HelloWorld.java -sourcepath src -d build -g 1 -sourcepath 表示 從指定的源文件目錄中找到需要的.java文件並進行編譯。 也可以用-cp指定編譯好的class的路徑 運行,注意:運行在build目錄下 E:codeplacen_learnjavajavacmdbuild>java com.yp.test.HelloWorld

怎麼打成jar包?

生成: E:codeplacenlearnjavajavacmdbuild>jar cvf h.jar * 運行: E:codeplacenlearnjavajavacmdbuild>java h.jar 錯誤: 找不到或無法載入主類 h.jar 這個錯誤是沒有指定main類,所以類似這樣來指定: E:codeplacen_learnjavajavacmdbuild>java -cp h.jar com.yp.test.HelloWorld

生成可以運行的jar包

需要指定jar包的應用程式入口點,用-e選項:

E:codeplacen_learnjavajavacmdbuild> jar cvfe h.jar com.yp.test.HelloWorld *  已添加清單  正在添加: com/(輸入 = 0) (輸出 = 0)(存儲了 0%)  正在添加: com/yp/(輸入 = 0) (輸出 = 0)(存儲了 0%)  正在添加: com/yp/test/(輸入 = 0) (輸出 = 0)(存儲了 0%)  正在添加: com/yp/test/entity/(輸入 = 0) (輸出 = 0)(存儲了 0%)  正在添加: com/yp/test/entity/Cat.class(輸入 = 545) (輸出 = 319)(壓縮了 41%)  正在添加: com/yp/test/HelloWorld.class(輸入 = 844) (輸出 = 487)(壓縮了 42%)

直接運行

java -jar h.jar    額外發現  指定了Main類後,jar包裡面的 META-INF/MANIFEST.MF 是這樣的, 比原來多了一行Main-Class….  Manifest-Version: 1.0  Created-By: 1.8.0 (Oracle Corporation)  Main-Class: com.yp.test.HelloWorld

如果類里有引用jar包呢?

先下一個jar包 這裡直接下 log4j

* main函數改成    import com.yp.test.entity.Cat;  import org.apache.log4j.Logger;    public class HelloWorld {        static Logger log = Logger.getLogger(HelloWorld.class);        public static void main(String[] args) {          Cat c = new Cat("keyboard");          log.info("這是log4j");          System.out.println("hello," + c.getName());      }    }

現的文件是這樣的

├─build  ├─lib  │      log4j-1.2.17.jar  │  └─src      └─com          └─yp              └─test                  │  HelloWorld.java                  │                  └─entity                          Cat.java
這個時候 javac命令要接上 -cp ./lib/*.jar  E:codeplacen_learnjavajavacmd>javac -encoding "utf8" src/com/yp/test/HelloWorld.java -sourcepath src -d build -g -cp ./lib/*.jar      運行要加上-cp, -cp 選項貌似會把工作目錄給換了, 所以要加上 ;../build  E:codeplacen_learnjavajavacmdbuild>java -cp ../lib/log4j-1.2.17.jar;../build com.yp.test.HelloWorld

結果:

log4j:WARN No appenders could be found for logger(com.yp.test.HelloWorld).  log4j:WARN Please initialize the log4j system properly.  log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.  hello,keyboard

由於沒有 log4j的配置文件,所以提示上面的問題,往 build 裡面加上 log4j.xml

<?xml version="1.0" encoding="UTF-8" ?>  <!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">  <log4j:configuration xmlns:log4j='http://jakarta.apache.org/log4j/'>      <appender name="stdout" class="org.apache.log4j.ConsoleAppender">          <layout class="org.apache.log4j.PatternLayout">              <param name="ConversionPattern" value="%d{ABSOLUTE} %-5p [%c{1}] %m%n" />          </layout>      </appender>        <root>          <level value="info" />          <appender-ref ref="stdout" />      </root>  </log4j:configuration>

再運行

E:codeplacen_learnjavajavacmd>java -cp lib/log4j-1.2.17.jar;build com.yp.tes t.HelloWorld  15:19:57,359 INFO  [HelloWorld] 這是log4j  hello,keyboard

說明: 這個log4j配置文件,習慣的做法是放在src目錄下, 在編譯過程中 copy到build中的,但根據ant的做法,不是用javac的,而是用來處理,我猜測javac是不能copy的,如果想在命令行直接 使用,應該是用cp命令主動去執行 copy操作

ok 一個簡單的java 工程就運行完了 但是 貌似有些繁瑣, 需要手動鍵入 java文件 以及相應的jar包 很是麻煩, so 可以用 shell 來腳本來簡化相關操作 shell 文件整理如下:

#!/bin/bash  echo "build start"    JAR_PATH=libs  BIN_PATH=bin  SRC_PATH=src    # java文件列表目錄  SRC_FILE_LIST_PATH=src/sources.list    #生所有的java文件列表 放入列表文件中  rm -f $SRC_PATH/sources  find $SRC_PATH/ -name *.java > $SRC_FILE_LIST_PATH    #刪除舊的編譯文件 生成bin目錄  rm -rf $BIN_PATH/  mkdir $BIN_PATH/    #生成依賴jar包 列表  for file in  ${JAR_PATH}/*.jar;  do  jarfile=${jarfile}:${file}  done  echo "jarfile = "$jarfile    #編譯 通過-cp指定所有的引用jar包,將src下的所有java文件進行編譯  javac -d $BIN_PATH/ -cp $jarfile @$SRC_FILE_LIST_PATH    #運行 通過-cp指定所有的引用jar包,指定入口函數運行  java -cp $BIN_PATH$jarfile com.zuiapps.danmaku.server.Main

有一點需要注意的是, javac -d $BINPATH/ -cp $jarfile @$SRCFILELISTPATH 在要編譯的文件很多時候,一個個敲命令會顯得很長,也不方便修改, 可以把要編譯的源文件列在文件中,在文件名前加@,這樣就可以對多個文件進行編譯, 以上就是吧java文件放到 $SRCFILELIST_PATH 中去了

編譯 :       1. 需要編譯所有的java文件       2. 依賴的java 包都需要加入到 classpath 中去       3. 最後設置 編譯後的 class 文件存放目錄  即 -d bin/       4. java文件過多是可以使用  @$SRC_FILE_LIST_PATH 把他們放到一個文件中去  運行:     1.需要吧 編譯時設置的bin目錄和 所有jar包加入到 classpath 中去

javap

javap是jdk自帶的一個工具,可以對程式碼反編譯,也可以查看java編譯器生成的位元組碼。 情況下,很少有人使用javap對class文件進行反編譯,因為有很多成熟的反編譯工具可以使用,比如jad。但是,javap還可以查看java編譯器為我們生成的位元組碼。通過它,可以對照源程式碼和位元組碼,從而了解很多編譯器內部的工作。 javap命令分解一個class文件,它根據options來決定到底輸出什麼。如果沒有使用options,那麼javap將會輸出包,類里的protected和public域以及類里的所有方法。javap將會把它們輸出在標準輸出上。來看這個例子,先編譯(javac)下面這個類。

import java.awt.*;  import java.applet.*;    public class DocFooter extends Applet {          String date;          String email;            public void init() {                  resize(500,100);                  date = getParameter("LAST_UPDATED");                  email = getParameter("EMAIL");          }  }

在命令行上鍵入javap DocFooter後,輸出結果如下

Compiled from "DocFooter.java"

public class DocFooter extends java.applet.Applet {    java.lang.String date;    java.lang.String email;    public DocFooter();    public void init();  }

如果加入了-c,即javap -c DocFooter,那麼輸出結果如下

Compiled from "DocFooter.java"

public class DocFooter extends java.applet.Applet {    java.lang.String date;      java.lang.String email;      public DocFooter();      Code:         0: aload_0         1: invokespecial #1                  // Method java/applet/Applet."<init>":()V         4: return      public void init();      Code:         0: aload_0         1: sipush        500         4: bipush        100         6: invokevirtual #2                  // Method resize:(II)V         9: aload_0        10: aload_0        11: ldc           #3                  // String LAST_UPDATED        13: invokevirtual #4                  // Method getParameter:(Ljava/lang/String;)Ljava/lang/String;        16: putfield      #5                  // Field date:Ljava/lang/String;        19: aload_0        20: aload_0        21: ldc           #6                  // String EMAIL        23: invokevirtual #4                  // Method getParameter:(Ljava/lang/String;)Ljava/lang/String;        26: putfield      #7                  // Field email:Ljava/lang/String;        29: return    }

上面輸出的內容就是位元組碼。

用法摘要

-help 幫助 -l 輸出行和變數的表 -public 只輸出public方法和域 -protected 只輸出public和protected類和成員 -package 只輸出包,public和protected類和成員,這是默認的 -p -private 輸出所有類和成員 -s 輸出內部類型簽名 -c 輸出分解後的程式碼,例如,類中每一個方法內,包含java位元組碼的指令, -verbose 輸出棧大小,方法參數的個數 -constants 輸出靜態final常量 總結

javap可以用於反編譯和查看編譯器編譯後的位元組碼。平時一般用javap -c比較多,該命令用於列出每個方法所執行的JVM指令,並顯示每個方法的位元組碼的實際作用。可以通過位元組碼和源程式碼的對比,深入分析java的編譯原理,了解和解決各種Java原理級別的問題。