前段時間看了一本書,說的是用go語言實作java虛擬機,很有意思,于是就花了一段時間學習了一下go語言,雖然對go的底層理解不是很深,但是寫代碼還是可以的,就當做個讀書筆記吧!
鏈接在這里,另外還有一本《go程式設計語言》,有需要的直接一起拿走,鏈接:https://pan.baidu.com/s/152ZX7cLf5IcOzUk1C_Q8JQ 提取碼:3ktm
首先我們知道java能夠跨平臺的原因就是class位元組碼檔案在不同的jvm中都可以運行,每個計算機都可以安裝符合自己作業系統的jvm,然后class檔案就可以通用了,而class檔案被包裝的形式有很多種,最常見的應該就是jar包,有興趣的可以看看打開自己的jdk中隨便的個jar包,里面其實就是一些class位元組碼檔案;
我們就簡單一點,我們自己把一個java原始碼檔案手動打包成一個jar包,下面的注釋已經很清楚了
//javac HelloWorld.java將一個java原始碼檔案編譯成class檔案 //java手動將class檔案打成jar包命令:jar cvf hello.jar HelloWorld.class //執行java -classpath hello.jar HelloWorld,表示執行hello中的jar包中HelloWorld中的main方法 public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, world!"); } }
打成jar包之后,我們現在手中的檔案有兩個,一個是HelloWorld.class位元組碼檔案,一個是hello.jar檔案(jar包其實就是一個壓縮包),我們分別用兩條命令執行這兩個檔案,不知道大家有沒有看出來什么?
如果是位元組碼檔案的話,就是直接用java xxx執行就行了;如果是jar包的形式,那么我們必須要指定jar包的全路徑,以及jar包里面main方法所在的位元組碼檔案,這樣jvm才能找到入口,就會在jar包中找到該檔案,然后運行;我們可以實作一下命令列的處理方式:

不知道大家還記不記得查看jdk版本的命令,就是java -version;在go語言中,對這種命令列引數的處理有兩種,一種是os.Args這個切片來處理,另外一種通過一個flag包,選用后者,flag包封裝了很多操作;
main.go代碼如下:
package main import "fmt" func main() { //同一個包下,私有方法也可以呼叫,如果是不同包,那就需要把parseCmd函式首字母大寫 cmd := parseCmd() //例如java -version,那么此時在parseCmd函式中決議version的值位true,然后賦值給versionFlag,就列印版本號 if cmd.versionFlag { fmt.Println("version 1.0.0") //例如輸入的是java -help或者是java -classpath hello.jar ,沒有加后面的類名,那么就呼叫printUsage函式 //列印提示資訊 } else if cmd.helpFlag || cmd.class == "" { printUsage() //當引數都輸入正確,那么就呼叫startJVM函式啟動jvm,這里暫時就列印一句話,將輸入的命令各部分引數都列印出來 } else { startJVM(cmd) } } func startJVM(cmd *Cmd) { fmt.Printf("classpath:%s class:%s args:%v\n", cmd.cpOption, cmd.class, cmd.args) }
cmd.go檔案內容:
package main import ( "flag" "fmt" "os" ) //簡單的定義一個結構體,這里保存命令列中輸入的引數 type Cmd struct { helpFlag bool versionFlag bool cpOption string class string args []string } func parseCmd() *Cmd { cmd := &Cmd{} //這里的意思就是如果決議失敗的話,就呼叫printUsage函式 flag.Usage = printUsage //決議命令列中輸入,例如java -help,那么這里help就是true,然后把true賦值給cmd結構體中helpFlag保存起來 //最后一個是默認資訊 flag.BoolVar(&cmd.helpFlag, "help", false, "print help message") //例如java -version,那么version就是true,賦值給cmd中的versionFlag flag.BoolVar(&cmd.versionFlag, "version", false, "print version and exit ") //例如java -classpath hello.jar HelloWorld,這里classpath就是hello.jar,然后賦值給cpOption保存起來 flag.StringVar(&cmd.cpOption, "classpath", "", "classpath") //上面是定義決議規則,呼叫Parse函式才是真正開始決議 flag.Parse() //決議成功的話,那就繼續獲取后面的引數,注意這里的args是一個切片型別的 //例如java -classpath hello.jar HelloWorld arg1,arg2,這里的args[0]表示HelloWorld,args[1:]表示arg1和arg2, //就是傳給main方法形參字串陣列的引數 args := flag.Args() if len(args) > 0 { cmd.class = args[0] cmd.args = args[1:] } return cmd } //這里傳進去的引數,決議錯誤的話就顯示第一個引數的提示資訊 func printUsage() { fmt.Printf("Usage:%s [-options] class [args]\n", os.Args[0]) }
其實很容易,然后我們可以測驗一下,目錄結構如下,其中main.go和cmd.go都在ch01中,我們進入到src目錄下,打開終端,輸入go install jvmgo\ch01,就會在workspace/bin下生成一個ch01.exe可執行檔案;


轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/38556.html
標籤:Go
上一篇:golang單元測驗簡述
下一篇:Gong服務實作平滑重啟分析
