2017年4月14日 星期五

java 編譯/執行環境 (0) - 單獨一個 java source code 檔案

寫完一個 java 程式後, 我想知道如何編譯它、如何執行它。哥是正統 unix 軟體開發人員, 沒在用 eclipse 這種按下去就編好的東西, 只用會讓自己難過的 command line 編譯方式。不過 java 的編譯還真不是普通的複雜, 如何執行它更是混亂。

list 1. HelloWorld.java
1
2 public class HelloWorld
3 {
4   public static void main(String[] args)
5   {
6     System.out.println("Hello World");
7   }
8 }

list 2. HelloWorld.class
1 descent@debian64:DescentPackage$ pwd
2 /media/work/git/progs/java/DescentPackage
3 descent@debian64:DescentPackage$ javac HelloWorld.java 
4 descent@debian64:DescentPackage$ ls -l HelloWorld.class
5 -rw-r--r-- 1 descent descent 425 Mar 30 09:44 HelloWorld.class
6 descent@debian64:DescentPackage$ java HelloWorld 
7 Hello World

看來好像沒什麼難的是吧? list 2 L6 看起來好像是把 HelloWorld.class 執行起來, 但 java HelloWorld 的 HelloWorld 並不是 HelloWorld.class 這個檔案, 實際上是 ...

先賣個關子, 加上 package namespace 試試。

HelloWorld.java
 1 package DescentPackage;
 3
 4 public class HelloWorld
 5 {
 6   public static void main(String[] args)
 7   {
 8     System.out.println("Hello World");
 9   }
10 }

啊哈, 可以用 javac 編譯出 HelloWorld.class

descent@debian64:DescentPackage$ javac HelloWorld.java 
descent@debian64:DescentPackage$ java HelloWorld 
Error: Could not find or load main class HelloWorld

但用 java 這個指令竟然無法執行成功, 亂試 ...

descent@debian64:DescentPackage$ java DescentPackage.HelloWorld
Error: Could not find or load main class DescentPackage.HelloWorld

果然還是不行,

descent@debian64:DescentPackage$ cd ..
descent@debian64:java$ ls DescentPackage/
a.jar             HelloWorld.java       MANIFEST.MF
HelloWorld.class  HelloWorld.java.html  PrintString.java
HelloWorld.jar    makefile              readme
descent@debian64:java$ java DescentPackage.HelloWorld
Hello World

疑, 可以執行了。但要在上一層才能執行覺得很不爽, 我就想在 DescentPackage/ 目錄中執行, 難道不可以嗎?

descent@debian64:java$ cd DescentPackage/
descent@debian64:DescentPackage$ java DescentPackage.HelloWorld
descent@debian64:DescentPackage$ java -cp .. DescentPackage.HelloWorld
Hello World

這樣應該有點感覺了吧! java 後面接的不是編譯出來的檔名, 而是 main class, 而在 package 裡頭的 main class 自然要加上 namespace, 也就是 DescentPackage.HelloWorld。這是第一個條件。

javac, java man page
1 javac [ options ] [ sourcefiles ] [ classes] [ @argfiles ]
2
3 java [options] classname [args]
4 java [options] -jar filename [args]

第二個條件就是 classpath, 要從哪裡開始找到這個 DescentPackage.HelloWorld main class,

java DescentPackage.HelloWorld

會從目前目錄開始找 HelloWorld.class 這個檔案, 如果目前目錄是 cc, 會從這裡往 DescentPackage/ (也就是 cc/DescentPackage/) 找 HelloWorld.class 這個檔案, 自然找不到, 建立一個 DescentPackage, 把 HelloWorld.class move 到 DescentPackage, java DescentPackage.HelloWorld 又成功執行了。

descent@debian64:DescentPackage$ mkdir DescentPackage
descent@debian64:DescentPackage$ mv HelloWorld.class DescentPackage/
descent@debian64:DescentPackage$ java DescentPackage.HelloWorld
Hello World
descent@debian64:DescentPackage$ pwd
/media/work/git/progs/java/DescentPackage
descent@debian64:DescentPackage$ ls
a.jar           HelloWorld.jar   HelloWorld.java.html  MANIFEST.MF       readme
DescentPackage  HelloWorld.java  makefile              PrintString.java
descent@debian64:DescentPackage$ ls DescentPackage/
HelloWorld.class


Java 編程語言 (The Java Programming Language, 4/e)
Ken Arnold、James Gosling、David Holmes 著
侯捷、柯向上 譯
那如果我就是要在 DescentPackage 目錄執行呢? 行! 告訴 java, 從上一層開始找 HelloWorld.class 就可以了。這是為什麼加上 -cp .. 的原因。

必須要知道 package name 和 classpath 才能正確執行 java 程式, 這是一個比較複雜的地方。

Java 編程語言 (The Java Programming Language, 4/e) 這本書完全沒寫到這個, 我覺得很不舒服, 如果連寫出來的程式都不知道怎麼編譯與執行, 還怎麼學這個程式語言呢?

ref:

沒有留言:

張貼留言

使用 google 的 reCAPTCHA 驗證碼, 總算可以輕鬆留言了。

我實在受不了 spam 了, 又不想讓大家的眼睛花掉, 只好放棄匿名留言。這是沒辦法中的辦法了。留言的朋友需要有 google 帳號。