顯示具有 Package 標籤的文章。 顯示所有文章
顯示具有 Package 標籤的文章。 顯示所有文章

2014年4月16日 星期三

套件 Package : 檔案的切割

Java 檔案未切割前

檔案:CarTest0.java
class Car {
   public void show() {
     System.out.println("Class Car");
   }
}

class CarTest0 {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
}
編譯程式 CarTest0.java
$ javac CarTest0.java
檢視目錄,發現編譯後新增 2 個類別檔案:Car.class 與 CarTest0.class
$ ls -l
total 48
-rw-r--r--  1 elvismeng  staff  389  4  3 11:56 Car.class
-rw-r--r--  1 elvismeng  staff  312  4  3 11:56 CarTest0.class
-rw-r--r--  1 elvismeng  staff  192  4  3 11:56 CarTest0.java
Java 檔案切割後

檔案:Car.java
class Car {
   public void show() {
     System.out.println("Class Car");
   }
}
在此,我們故意將類別名稱 CarTest 的命名與其儲存檔案的名稱 CarTest1.java 不相同。 檔案:CarTest1.java
class CarTest {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
}
編譯程式。
$ javac CarTest1.java
檢視目錄,發現目錄下編譯後新增加 2 個類別檔案:Car.class 與 CarTest.class。編譯後,原始程式儲存的檔案名稱 CarTest1.class 與其類別名稱不同,而編譯後會以類別名稱來產生一個新的類別檔案 CarTest.class。
$ ls -l
total 48
-rw-r--r--  1 elvismeng  staff  384  4  3 11:35 Car.class
-rw-r--r--  1 elvismeng  staff   81  4  3 11:35 Car.java
-rw-r--r--  1 elvismeng  staff  311  4  3 11:35 CarTest.class
-rw-r--r--  1 elvismeng  staff  109  4  3 11:33 CarTest1.java

執行結果。
$ java CarTest

Class Car


套件 Package: 用 package 管理 - 檔案切割後


Java 檔案切割後

隸屬在同一個 package 資料夾

檔案:Car.java
package test1;

class Car {
   public void show() {
     System.out.println("Class Car");
   }
}  
檔案:CarTest1.java
package test1;

class CarTest {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
} 
編譯程式。我們讓系統自動產生儲存這些 class 檔案所在的資料夾 test1
$ javac -d ./ Car.java CarTest1.java
檢視編譯結果:
$ ls -l test1
total 16
-rw-r--r--  1 elvismeng  staff  390  4  3 12:58 Car.class
-rw-r--r--  1 elvismeng  staff  323  4  3 12:58 CarTest.class   
執行程式
$ java test1.CarTest

Class Car


隸屬在不同的 package 資料夾

檔案:Car.java
package test2_1;

class Car {
   public void show() {
     System.out.println("Class Car");
   }
}  
檔案:CarTest1.java
package test2_2;

class CarTest {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
} 
編譯時,發生錯誤。為什麼?
ElvisdeMacBook-Pro:PackageManual elvismeng$ javac -d ./ Car.java CarTest1.java
CarTest1.java:5: error: cannot find symbol
     Car car = new Car();
     ^
  symbol:   class Car
  location: class CarTest
CarTest1.java:5: error: cannot find symbol
     Car car = new Car();
                   ^
  symbol:   class Car
  location: class CarTest
2 errors
這是因為兩個類別位於不同的 package,而無法存取對方,程式需改成

檔案:Car.java

package test2_1;

class Car {
   public void show() {
     System.out.println("Class Car");
   }
}


檔案:CarTest1.java

package test2_2;

class CarTest {
   public static void main(String args[]){
     test2_1.Car car = new test2_1.Car();
     car.show();
   }
}
編譯時,為何又有錯誤產生?
ElvisdeMacBook-Pro:PackageManual elvismeng$ javac -d ./ CarTest1.java
CarTest1.java:5: error: Car is not public in test2_1; cannot be accessed from outside package
     test2_1.Car car = new test2_1.Car();
            ^
CarTest1.java:5: error: Car is not public in test2_1; cannot be accessed from outside package
     test2_1.Car car = new test2_1.Car();
                                  ^
2 errors
錯誤原因在 Car 的存取權限要設為 public,所以程式需做下列修改

檔案:Car.java

package test2_1;

public class Car {
   public void show() {
     System.out.println("Class Car");
   }
}


檔案:CarTest1.java

package test2_2;

class CarTest {
   public static void main(String args[]){
     test2_1.Car car = new test2_1.Car();
     car.show();
   }
}
重新編譯
$ javac -d ./ Car.java
javac -d ./ CarTest1.java
編譯後會產生下列 package 資料夾與其相關類別檔案
$ ls -l test2_1
total 8
-rw-r--r--  1 elvismeng  staff  392  4  3 13:46 Car.class

$ ls -l test2_2
total 8
-rw-r--r--  1 elvismeng  staff  327  4  3 13:46 CarTest.class
執行結果
$ java test2_2.CarTest

Class Car

套件 Package: 用 package 管理 - 檔案未切割前

package 宣告語法
   package  package名稱 ;

Java 檔案未切割前

檔案:CarTest0.java
package test0;

class Car {
   public void show() {
     System.out.println("Class Car");
   }
}

class CarTest0 {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
}
編譯後,正常,同時新增 2 個類別檔案:Car.class 與 CarTest0.class
$ javac CarTest0.java

ls -l
total 48
-rw-r--r--  1 elvismeng  staff  395  4  3 12:13 Car.class
-rw-r--r--  1 elvismeng  staff  324  4  3 12:13 CarTest0.class
-rw-r--r--  1 elvismeng  staff  208  4  3 12:12 CarTest0.java
執行時,系統回饋錯誤訊息,為什麼?
$ java CarTest0
Exception in thread "main" java.lang.NoClassDefFoundError: CarTest0 (wrong name: test0/CarTest0)
 at java.lang.ClassLoader.defineClass1(Native Method)
 at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
 at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
 at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
 at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
 at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
 at java.security.AccessController.doPrivileged(Native Method)
 at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
 at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
 at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
 at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
這是因為我們在 CarTest0.java 第一行新增 package test0; 即將這類別包裝在 test0 這套件中。套件 package 在實體上可被視為檔案夾,因此,我們手動新增一個資料夾,此資料夾必須與程式中的 package名稱一致,在這裏我們新增一個資料夾為 test0,然後將程式移入到此資料夾中。

編譯程式
$ javac test0/CarTest0.java
檢視編譯後結果
$ ls -l test0

total 24
-rw-r--r--  1 elvismeng  staff  395  4  3 12:21 Car.class
-rw-r--r--  1 elvismeng  staff  324  4  3 12:21 CarTest0.class
-rw-r--r--  1 elvismeng  staff  208  4  3 12:12 CarTest0.java
執行結果
$ java test0.CarTest0

Class Car

若不想手動新增資料夾,可用 javac -d 的指令由系統產生
$ javac -d ./ CarTest0.java
檢視編譯結果
$ ls -l test0

total 16
-rw-r--r--  1 elvismeng  staff  395  4  3 12:36 Car.class
-rw-r--r--  1 elvismeng  staff  324  4  3 12:36 CarTest0.class

套件 Package: 用 package 管理 - 匯入 import

檔案:Car.java
package test3_1;

public class Car {
   public void show() {
     System.out.println("Class Car");
   }
}
檔案:CarTest1.java
package test3_2;
import test3_1.Car;

class CarTest {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
}
編譯程式
$ javac -d ./ Car.java CarTest1.java
檢查編譯後結果
$ ls -l test3_1
total 8
-rw-r--r--  1 elvismeng  staff  392  4  3 14:07 Car.class

$ ls -l test3_2
total 8
-rw-r--r--  1 elvismeng  staff  327  4  3 14:07 CarTest.class
執行程式
$ java test3_2/CarTest

Class Car

建立 subpackage

我們可在 package 底下,再建立一個 subpackage,將性質、功能相近的類別彙集在同一個 package 當中,會變得更容易管理。

用這方法可建立出 package 與 package 的階層關係,但是要注意 package 與 subpackage 不必有絕對的裙帶關係,只要根據功能別加以適當分類就好。

檔案: Car.java
package test4_1.sub;

public class Car {
   public void show() {
     System.out.println("Class Car");
   }
}
檔案: CarTest1.java
package test4_2;
import test3_1.Car;

class CarTest {
   public static void main(String args[]){
     Car car = new Car();
     car.show();
   }
}
編譯程式
$ javac -d ./ Car.java CarTest1.java
檢視編譯後結果
$ ls -l test4_1/sub
total 8
-rw-r--r--  1 elvismeng  staff  396  4  3 14:18 Car.class

$ ls -l test4_2
total 8
-rw-r--r--  1 elvismeng  staff  327  4  3 14:18 CarTest.class
執行結果
$ java test4_2/CarTest

Class Car

匯入 import 多個類別

我們可一口氣以萬用字 * 匯入多個 package
import java.io.*

但記住:subpackage 與 package 有階層形式,但沒有實質上的裙帶關係,所以匯入時要特別設定
import java.awt.*;
import java.awt.image.*;
另外要提的是,程式若沒有匯入任何 package,事實上系統是用預設的 java.lang。