第 13 章 套件 (Packages).

Slides:



Advertisements
Similar presentations
软件编程基础 一、程序的编辑 Java 源程序是以 Java 为后缀的简单的文本文件,可以用各种 Java 集成开发环境中的源代码编辑器来编写,也可以用其他文 本编辑工具,如 Windows 中的记事本或 DOS 中的 EDIT 软件等。 利用文字编辑器编写下列程序 public class Hello.
Advertisements

Java 大学实用教程 ( 第 3 版 ) 主讲:程继洪 第 1 章 Java 语言概述  本章导读 Java 语言的诞生Java 语言的诞生 学习 Java 的必要性 学习 Java 的必要性 Java 的特点及与 C/C++ 之关系Java 的特点及与 C/C++ 之关系.
第 2 章 Java 运行环境搭建 2.1 Java 的运行系统 2.1 Java 的运行系统 2.2 JDK 的安装与配置2.2 JDK 的安装与配置 2.3 Java 开发工具包 2.4 Java 源文件编辑环境的选择 2.5 Application 和 Applet 程序的编写与运行.
1 Java 语言程序设计 计算机系 鲍金玲. 2 引子 甲骨文 甲骨文是全球最大的信息管理软件及服务供应商,成立于 1977 年,公司总部 设在美国加利福尼亚州的红木城( Redwood Shores ),全球员工达 名, 包括 名开发人员、 7500 多名技术支持人员和.
Java 程序分类 Java Application :是完整程序,需要独立的解 释器解释运行;以 “.java” 为后缀的文件,以 main() 方法作为程序入口,由 java 编译器编译生 成字节码,由 Java 解释器加载执行字节码。 Java Applet 没有 main() 方法作为程序入口,是嵌在.
第一章 Java 程序设计技术 概述  什么是 Java 语言  一个简单的 Java 程序  程序的编译和运行  常见错误  使用 Java 核心 API 文档.
程序设计语言基础 软件工程系 秦晓燕. 课程目标 了解面向对象程序设计的思想,以及软件 开发流程。 学习 Java 语言的基本概念和编程方法,基 本掌握 Java 类库的使用。 能够利用所学的方法开发简单的小型应用 程序.
Java 程序设计 案例教程 北京大学出版社 第 01 章. Java 程序设计案例教程 第 01 章 Java 语言与面向对象程序设计 Java 语言的历史 Java 语言的特点 Java 程序的分类 Java 环境配置 Eclipse 的安装 Java 程序的调试 教学目标.
Java 程序设计(第二版) 普通高等教育 “ 十一五 ” 国家级规划教材 辛运帷等 编著 徐小平 主讲.
系統分析與設計 楊子青 H-1 H 、物件導向技術 n 物件導向的基本概念 – 物件、類別 – 封裝、繼承 – 同名異式 ( 多型 ) 、超荷 ( 過載 ) n 物件導向分析與設計及塑模工具 n UML 塑模工具.
第6章 对象和类.
单元二:面向对象程序设计 任务二:借书卡程序设计.
3.2 Java的类 Java 类库的概念 语言规则——程序的书写规范 Java语言 类库——已有的有特定功能的Java程序模块
JAVA 编 程 技 术 主编 贾振华 2010年1月.
第 9 章 物件的建構.
6. 6 Overloading methods and constructors 6
《 Java开发环境配置》 主讲人:耿力.
Java 2实用教程(第3版)教学课件 主讲教师:张国平
学生教育办介绍 2015年9月.
Java程序设计教程 第一讲 Java概述.
Java的程式架構與基本觀念 Java語言的歷史 Java程式的開發環境 Java程式的架構 輸出與輸入物件之使用 工具使用方法介紹
第4章 类与对象 本章导读 0. 面向对象编程 1. 类声明和类体 2. 类体的构成 3. 构造方法与对象的创建 4. 对象的引用与实体
《Java程序设计之网络编程》 教学课件 重庆大学计算机学院
北京科技大学天津学院 信息工程系 面 向 对 象 程 序 设 计 第1讲 Java初探 主讲:于静.
程設一.
第1章 java简介及环境搭建 第1章 Java简介及开发环境搭建.
類別的繼承-一般關係: 繼承是宣告的類別繼承現存類別的部份或全部的成員資料和方法 , 新增額外的成員資料和方法或覆寫和隱藏繼承類別的方法
JAVA程序设计 (03) JAVA Programming
第9章 单例模式 Website:
第5章 Java中类、对象、接口 及包的概念 5.1 类的基本概念 5.2 类的继承概念 5.3 抽象类和接口 5.4 包.
Android App 系統開發教學 Luna 陳雯琳 2014/12/18
Qtopia 编程部分要点分析 苗忠良.
第5章 面向对象程序设计 本章要点 5.1 面向对象程序设计概述 5.2 Java语言的面向对象程序设计 5.3 方法的使用和对象数组
H、物件導向技術 物件導向的基本概念 物件、類別 封裝、繼承 同名異式(多型) 、超荷(過載) 物件導向分析與設計及塑模工具 UML塑模工具.
物件導向程式設計 (Object-Oriented rogramming)
JDK的安裝.
陈炎 南京大学软件学院 Ant简介 Ant一个优秀的构建工具 Ant意思是Another Neat Tool 陈炎 南京大学软件学院
2018/11/20 第一章 Java概述 武汉大学计算机学院计算机应用系 2018/11/20 14:33.
Classes Lecturer: 曾學文.
CHAPTER 9 建構方法 ROBERT.
實作輔導 日期: 3/11 09:10~16:00 地點:臺北市立大學 臺北市中正區愛國西路一號 (中正紀念堂站7號出口)
第六章 类的扩展与继承.
程式設計實作.
抽象类 File类 String类 StringBuffer类
CH09 套件 物件導向程式設計(II).
Java软件设计基础 5. 继承与多态.
2018/12/7 Java语言程序设计 教师:段鹏飞.
Java基础入门 第1章 Java开发入门 · Java语言的特点 · Java开发环境的搭建 · 环境变量的配置 · Java的运行机制.
類別的繼承 Vehicle Car.
中国矿大计算机学院杨东平 第5章 接口和包 中国矿大计算机学院杨东平
辅导课程九.
第一章 Java语言概述.
二:JAVA开发环境的安装和配置.
第5讲 使用类和对象编程(三) 内部类 实例 程序控制结构 选择语句.
Microsoft SQL Server 2008 報表服務_設計
面向对象 程序设计语言基础 马骏
開發Java程式語言的工具 JDK.
Java程式初體驗大綱 大綱 在學程式之前及本書常用名詞解釋 Hello Java!程式 在Dos下編譯、執行程式
Interfaces and Packages
第二章 Java基本语法 讲师:复凡.
第6章 面向对象的高级特征 学习目标 本章要点 上机练习 习 题.
code::blocks 與GLUT 程式開發
JAVA 程式設計與資料結構 第三章 物件的設計.
第4讲 类和对象、异常处理 ggao.
對於成員(member)存取權的限制 成員的資料被毫無限制的存取,任誰都可以指定任意值給成員,Java語言為了防止這種現象的產生,規定:有一種成員的資料不能任由類別外部的任何人隨意存取。
Usage Eclipse 敏捷方法工具介紹 實驗室網站:
第 2 章 初探 Java.
輸出執行結果到螢幕上 如果要將執行結果的文字和數值都「輸出」到電腦螢幕時,程式要怎麼寫? class 類別名稱 {
第6章 继承和多态 伍孝金
Summary
Presentation transcript:

第 13 章 套件 (Packages)

學習目標 瞭解套件 (Packages) 適當的組織程式 撰寫通用於多個程式的公用類別 使用套件避免名稱的重複 將套件打包為 JAR 壓縮檔 熟悉編譯與執行時的參數設定

前言 當我們撰寫的程式越來越複雜、程式碼也愈來愈多行的時候, 會發現將所有的類別全部寫在同一個檔案中並不是個好作法, 因為這會讓整個程式看起來很複雜, 想要找到某個類別的某個方法時也必須耗費一番功夫。 此外, 有些類別, 例如前幾章範例中出現的二分搜尋法或排序的類別, 在設計時, 就是希望可以提供給不同的程式使用, 如果直接寫在個別程式檔中, 就無法凸顯該類別可供不同程式採用的特性。

前言 更進一步來看, 如果類別要分享給其他人使用, 那麼很可能發生我們寫的類別與他人寫的類別名稱衝突的情況。 但是別人不一定能夠修改我們的類別名稱 (沒有原始碼), 使對方被迫修改可表達類別意義的名稱。 在這一章中, 就要針對上述的問題, 說明 Java 所提供的解決方案 ― 套件, 討論適當組織程式以及分享特定類別的方法。

13-1 程式的切割 當程式越來越大的時候, 最簡單的整理方式就是讓每一個類別單獨儲存在一個原始檔案中, 並為個別的檔案以所含的類別名稱為主檔名 (副檔名當然仍是 . java), 並將程式所需的檔案全部放在同一個目錄中。 舉例來說, 上一章的幾何圖形類別範例, 我們即可將 Shape 、Circle、Cylinder、 Rectangle 這幾個類別都個別存於 Shape.java、Circle.java、Cylinder.java、Rectangle.java 這四個檔案中。

程式的切割 而需要用到這些類別的程式則自成一個檔案, 並與前述的檔案都放在一起 (您可以在書附光碟 Ch13/13-1 的資料夾中看到這些檔案)。

程式的切割 接著, 當我們編譯 UsingOtherClasses.java 時, Java 編譯器就會自動尋找含 Circle、Cylinder、Rectangle 類別的程式檔, 並也一併編譯這些檔案。 同樣在執行時, "java" 執行程式也會自行找到相關的類別檔, 讓程式可正常執行。 其實 Java 編譯器也會自動到環境變數 CLASSPATH 所設的路徑尋找類別檔, 或是到執行 javac 時所指定的路徑尋找, 此部份會在本章稍後說明。

程式的切割 使用單獨的檔案來儲存個別類別有以下好處: 管理類別更容易:只要找到與類別同名的檔案, 就可以找到類別的原始程式, 而不需要去記憶哪一個檔案中撰寫了那個類別, 或者是某個類別究竟是在那個檔案中。 編譯程式更簡單:只要編譯包含有 main( ) 方法的類別原始檔案, 編譯器就會根據使用到的類別名稱, 在同一個資料夾下找出同名的原始檔, 並進行必要的編譯。以本例來說, 雖然總共有 5 個原始檔案, 但在編譯UsingOtherClasses.java 時, Java 編譯器就會自動發現程式中需要使用到其他 4 個類別, 並自動編譯這 4 個類別的原始程式檔。

程式的切割 也就是說, 雖然程式切割為多個檔案, 但是在編譯及執行上並沒有增加任何的複雜度, 反而讓程式更易於管理。(即使不切割程式, 在編譯後仍是一個類別產生一個同名的類別檔。) 請特別注意, 這些檔案必須放置在同一個資料夾下, 而且檔名要和類別名稱一樣, 否則 Java 編譯TTIIPP 器並不知道要到哪裡找尋所需類別的原始檔案, 導致編譯錯誤。

程式的切割 如果原始檔名和類別名稱不同, 則可先編譯所有需要的原始檔 (使用 javac src1 src2, src3..., 也可用 * 做為萬用字元), 以產生和類別同名的類別檔, 這樣在編譯或執行主類別時, 就不會找不到其他類別了。

13-2 分享寫好的類別 有些情況下, 我們所撰寫的類別也可提供給其他人使用, 尤其是在開發團隊中, 讓開發人員不需重複撰寫類似功能的類別。 要做到這一點, 最簡單的方式, 就是將該類別的 .java 或 .class 檔案複製到別人的電腦上, 不過使用這種方式時, 對方的程式中不能有任何類別或是介面和我們所提供的類別同名。 遇到這種狀況時, 要不就是修改他自己的類別名稱, 要不就是修改你所提供的類別名稱, 不僅徒然浪費時間, 也同時增加了修改過程中發生錯誤的機會。

分享寫好的類別 為了解決上述問題, Java 提供套件 (Packages) 這種可將類別包裝起來的機制。 將類別包裝成套件時, 就相當於替類別貼上一個標籤 (套件名稱) , 而使用到套件中的類別時, 即需指明套件名稱, 因此可與程式中自己撰寫的同名類別區隔開來, 而不會混淆, 也沒有重新命名的問題。

13-2-1 建立套件 要將類別包裝在套件中, 必須在程式最開頭使用package 敘述, 標示出類別所屬的套件名稱, 以 Shape 類別為例, 如果要將之包裝在 "flag" 這個套件中, 可寫成:

建立套件

建立套件 除了第 1 行的 package 敘述外, 還要注意第 3 行的類別定義, 將類別存取控制宣告為 public, 這是因為如果不宣告為 public, 則該類別就無法由 package 以外的程式使用。 然而如上所述, 我們要使用 package 的原因就是希望解決類別提供給別人使用的問題, 所以當然要將 package 中的類別宣告為 public。 如果 package 中有只供自己使用的類別, 則可不宣告為 public。

建立套件 其它幾個類別原始檔的修改方式也類似, 都是加上 package 敘述, 並將類別宣告為 public 即可 (修改的結果可參考光碟中 Ch13/13-2/flag 資料夾中的檔案)。 在各檔案都做好相同的修改, 這些類別就算是都屬於我們指定的 flag 套件了, 未來即使類別名稱和其他套件名稱重複, 也完全沒有關係。

13-2-2 編譯包裝在套件中的類別 當類別使用 package 敘述指明所屬的套件之後, 在編譯類別時必須有額外的處理, 可以選擇以下兩種方式來整理及編譯這些類別: 自行建立套件資料夾:在 Java 中, 同一套件的類別必須存放在與套件名稱相同的資料夾中, 然後才能供其他程式使用。例如我們先將類別原始檔都放在與套件同名的 flag 資料夾, 接著用 javac 一一編譯, 編譯好的 .class 檔案也會存於其中。

編譯包裝在套件中的類別 由編譯器建立套件資料夾:我們也可將建立套件資料夾的動作交給 javac 編譯器處理, 只需在編譯時用參數 -d 指定編譯結果的儲存路徑, 編譯器就會根據 package 敘述指定的套件名稱, 在指定的路徑下建立與套件同名的子資料夾, 並將編譯結果存到該資料夾中。舉例來說, 如果要將 flag 套件放在 C:\Ch13\13-2 的資料夾下, 那麼就可以在編譯 Shape.java 時執行如下的命令:

編譯包裝在套件中的類別 javac 的 -d 參數原本是用來指定存放編譯結果的路徑, 在編譯不含 package敘述的程式時, 編譯好的 .class 檔會直接存於 -d 參數所指的路徑中;但編譯像 Shape.java 等第一行有 package 敘述的程式時, 則會在指定的路徑下, 另建套件資料夾, 以上例而言, 就是在 C:\Ch13\13-2 之下建立 flag 子資料夾, 並將編譯好的 .class 檔案放到 flag 資料夾中。 使用 -d 選項時, 所指定要放置套件的資料夾必須已經存在, 否則編譯時會發生錯誤。以剛剛的範例來說, 就是 C:\Ch13\13-2 這個資料夾必須已經存在。

編譯包裝在套件中的類別 無論使用哪一種方式, 一旦編譯好類別檔案, 並且放置到正確的資料夾中, 其他程式就可以使用包在套件中的類別了。

13-2-3 使用套件中的類別 要使用套件中的類別時, 必須以其完整名稱 (Fully Qualified Name) 來表示, 其格式為『套件名稱.類別名稱』。 以使用 flag 套件中的 Circle 類別為例, 就必須使用 flag.Circle 來表示, 請看以下的程式。

使用套件中的類別 此檔案存於範例程式資料夾 Ch13\13-2 之中。

使用套件中的類別 在第 3〜5 行中, 不論是物件宣告或是呼叫建構方法時, 都是使用『flag.類別名稱』的語法來使用 flag 套件中的類別。 而編譯及執行 UsingPackage.java 時, 由於使用到套件中的類別, 所以必須要有額外的處理, 我們區分為兩種狀況來說明。

套件與程式檔在同一資料夾下 如果套件和使用到套件的程式 (例如 UsingPackage.java) 都放在同一資料夾下, 那麼仍是以一般的方式編譯、執行即可。 例如 UsingPackage.java 存於 Ch13\13-2 資料夾中, 而 flag 套件則是存於同一路徑下的 flag 子資料夾, 那麼要編譯及執行 UsingPackage.java就可以這樣做:

套件與程式檔在同一資料夾下 當 Java 編譯器及虛擬機器看到 flag.* 的類別名稱時, 就會自動到程式所在的資料夾尋找是否有 flag 子資料夾。 如果有, 就在此資料夾下尋找是否有所指定的類別檔案, 並確認此類別屬於 flag 套件。 如果一切無誤, 就可以正常執行, 否則就會出現編譯錯誤。 舉例來說, 如果 flag 資料夾中沒有 Rectangle.java 或 Rectangle.class 檔案, 編譯時會出現如下錯誤。

套件與程式檔在同一資料夾下

套件與程式檔在同一資料夾下 此外如果編譯好後, 不小心將 flag 資料夾中的檔案移動位置或刪除, 則執行程式時也會出現找不到類別的訊息。 如果只是移動了位置, 可利用下一小節的方式讓 java 可找到套件的類別檔。

套件與程式在不同資料夾下 由於套件多半是提供給多人或是多個不同的程式共用, 所以當套件發展完畢時, 一般都會放置在某個特定的位置, 以方便不同的程式取用。 也就是說, 套件所在的資料夾通常並非使用該套件的程式所在的資料夾, 此時在編譯及執行程式時, 就必須告訴 Java 編譯器以及 Java 虛擬機器套件所在的位置。

套件與程式在不同資料夾下 舉例來說, 如果 flag 套件資料夾是放在 C:\Allpackages 之下, 而 UsingPackage.java 仍是放在前述的範例路徑中, 那麼要編譯與執行時, 就必須用 -cp 選項指出 flag 套件所在的路徑:

套件與程式在不同資料夾下 其中, -cp 選項意指 classpath, 也就是類別所在的路徑, Java 編譯器以及虛擬機器會到此選項所指定的資料夾中尋找所需的類別檔案。 若需要列出多個路徑, 可用分號連接, 如此 Java 編譯器以及虛擬機器就會依照指定的順序, 依序到各個資料夾中找尋所需的類別, 如果程式使用到了位於不同資料夾的套件或是類別, 就必須如此指定。

套件與程式在不同資料夾下 本例由於執行時所需的 UsingPackage.class 檔是位在自己的資料夾, 因此還要在cp選項所列的路徑中加上 "." , 否則會因為在 C:\Allpackages 下找不到UsingPackage.class 檔而發生執行時期錯誤。 一旦指定了 classpath, 就不會自動在目前的資料夾中尋找類別檔了, 因此別忘了在 classpath 中加上 "."。 "." 代表目前目錄, 而 ".." 則代表目前目錄的上一層目錄。若是在 Unix/Linux 的系統, 則路徑中的 "\" 要改成 "/", 而各路徑之間要以 : 分隔 (而非 ;)。在 SCJP 考題中, 有時會以 Unix 的路徑表示法來出題。

套件與程式在不同資料夾下 -cp 選項也可以使用全名寫成 -classpath, 兩者效用相同。 如果常常會使用到某個資料夾下的套件或是類別, 也可以設定環境變數 classpath, 就不需要在編譯或是執行時額外指定 -cp 或是 -classpath 選項, 例如。

套件與程式在不同資料夾下 Java 會優先搜尋內建類別所在的路徑, 然後再搜尋 classpath 所指定的路徑。當classpath 中有多個路徑時, 則會由最前面的路徑開始往後尋找, 一旦找到所需檔案即停止搜尋, 而不管後面的路徑中是否還有同名的檔案。

13-3 子套件以及存取控制關係 當程式越來越大時, 單一套件中可能會包含多個類別。 舉例來說, 上一章綜合演練所撰寫用來幫助陣列排序的 Sort 類別也很適合放到套件中供其他人使用。 要做到這一點, 只要將 Sort 類別以及伴隨的 ICanCompare 介面分別加上 package 敘述存檔編譯即可。

子套件以及存取控制關係 再次提醒, 需將編譯好的 .class 檔自行放到 flag 子資料夾;或在編譯時加上 -d 選項。

子套件以及存取控制關係 底下則是 Sort 類別:

子套件以及存取控制關係

子套件以及存取控制關係 這樣一來, 所有的程式都可以利用 Sort 類別來幫陣列排序了。 底下這個程式和上一章綜合演練的 Sorting.java 基本上是一樣的, 差別只在於 Sort 與ICanCompare 現在是包裝在 flag 套件中, 因此在程式中必須以 flag.Sort 以及 flag.ICanCompare 來識別。

子套件以及存取控制關係

子套件以及存取控制關係

子套件以及存取控制關係

子套件以及存取控制關係

子套件以及存取控制關係

13-3-1 在套件中建立子套件 如果加上原本就有的 Shape 第 4 個形狀類別, 則 flag 套件就有 5 個類別、1 個介面。 而當套件中的類別、介面愈來愈多時, 為了進一步將套件分類管理, 我們可進一步在現有套件中建立子套件, 把相關的類別集合起來, 歸於某一個子套件, 而這個子套件則和其他的類別或是子套件同屬於一個上層套件中。

在套件中建立子套件 舉例來說, 如果要將 Shape 等形狀類別歸屬於 math 套件中, 以表示其屬於數學幾何圖形類別的特性, 但又希望它仍舊屬於 flag 套件, 以表示其為旗標公司所提供, 那麼就可以在 flag 套件中建立名稱為 math 的子套件, 並將形狀類別放入 math 子套件中;而 ICanCompare 介面以及 Sort 類別則仍保留在flag 套件中。 要做到這一點, 需將程式中的 package 敘述所設定的套件名稱, 改成『套件.子套件』的形式, 例如。

在套件中建立子套件 此範例程式放置於 Ch13\13-3 子資料夾中。

在套件中建立子套件 這個版本和 13-1 節的版本完全一樣, 只有一開頭的 package 敘述後面所指的套件名稱不同, flag.math 這個名稱就表示其屬於 flag 套件下的子套件math 。 子套件類別的 .class 檔也一樣要放在與子套件同名的資料夾下, 換句話說, 我們必須將 Shape.class 檔需放在 flag\math 資料夾中。 由於牽涉了多層資料夾, 因此要編譯這個程式, 最簡單的方式就是使用前面介紹過的 -d 選項,讓 Java 編譯器幫我們依據套件的結構建立對應的資料夾。

在套件中建立子套件 假設要將 flag 套件的資料夾放在目前工作路徑下, 那麼編譯的指令就是: 將 Shape 等相關類別放入子套件後, 參考這些類別時所用的『完整名稱』就必須包含子套件名稱, 例如 flag.math.Circle, 請參考以下範例。

在套件中建立子套件 主要的變化就只是在使用子套件類別時, 都改用『flag.math.類別名稱』的形式。

在套件中建立子套件 如果有必要再對子套件中的類別和介面加以分類, 仍可在子套件中再建立下層的子套件, 只要在 package 敘述中使用.連接完整子套件的名稱即可。 相對的, 我們也必須自行手動、或是使用編譯器的 -d 選項建立對應的子套件資料夾, 並且將編譯好的 .class 檔案放到正確的資料夾中。 在執行的時候, 只需指定最上層套件所在的位置即可。

13-3-2 使用 import 敘述 如果子套件結構較多層時, 每次要使用一長串完整名稱來標識類別或介面, 不管是編寫或閱讀都會感到不便。

使用 import 敘述 import 敘述的功用, 是將指定的套件類別、或套件名稱『匯入』目前程式的名稱空間中, 此後要使用該類別或該套件中的類別時, 即可單純以其類別名稱來識別, 而不需冠上套件名稱, 簡化程式的撰寫。 使用 import 敘述的方式可分為兩種方式:匯入單一類別、或匯入套件。

匯入指定套件中的單一類別 import 敘述最簡單的使用方式, 就是直接匯入指定套件中的單一個類別, 例如:

匯入指定套件中的單一類別 程式第 1 行就是用 import 敘述匯入 flag.math 套件中的 Rectangle 類別的名稱, 所以之後直接用 Rectangle 這個名稱即可使用該類別, 但使用同一套件中的其它類別時, 則仍是要撰寫完整名稱。

匯入指定套件中所有的類別名稱 如果程式同時要用到同一套件中的多個類別, 並不需撰寫多行 import 敘述一一匯入所要用到的類別名稱, 而可用萬用字元*, 表示要匯入指定套件中所有的類別名稱。 例如, 上一個程式可改成。

匯入指定套件中所有的類別名稱

匯入指定套件中所有的類別名稱 由於第 1 行用 "import flag.math.*" 敘述匯入 flag.math 套件中所有的類別, 因此在程式中使用該套件的類別時, 就不再需要使用完整名稱, 亦可參考到套件中的類別。 但要特別注意, 萬用字元只代表該套件下的所有類別, 而不包含其下的子套件。舉例來說, 如果將 ImportPackage.java 的第一行改成:

匯入指定套件中所有的類別名稱 表示只匯入 flag.* 類別或介面, 但未匯入 flag.math 子套件下的類別或介面, 因此編譯到第 5、6 行時就會發生錯誤, 因為事實上未匯入子套件 flag.math 中的類別名稱, 所以編譯器就不知道第 5、6 行的 Rectangle、Circle 所指為何。 當 package 和 import 都有時, package 必須寫在最前面, 然後是 import, 再來才是 class 的定義。請務必記住這個順序。

13-3-3 使用 import static 敘述 前面介紹 import 可匯入指定套件中的某個類別 (或所有類別) 的名稱, 以便在程式中可以少打一些字 (只打類別名稱, 而省略套件名稱)。 如果類別中也有靜態成員 (變數或方法), 那麼還可用 import static (靜態匯入) 來再少打一些字 (只打成員名稱), 例如:

使用 import static 敘述 由於 out 是 System 類別的靜態成員, 而 toHexString()、MAX_VALUE 也是 Integer 類別的靜態成員, 因此可以將程式改寫如下 (以上粗體的字都可省略):

使用 import static 敘述 這樣是不是省事多了呢!不過在省事之餘, 卻也降低了程式的可讀性 (例如 MAX_VALUE 倒底是哪裡冒出來的?), 所以是否要使用這項功能, 就留給讀者自行決定了。 另外有一點要注意, 如果同時 import 了多個套件, 那麼不同套件之間若有名稱相同的類別, 則會造成編譯錯誤。

使用 import static 敘述 同理, 若使用 import static 匯入了多個類別, 那麼也有可能發生靜態成員名稱重複的狀況, 例如: 由於 Integer 和 Double 中都有 MAX_VALUE 靜態常數, 因此在程式中使用到 MAX_VALUE 時就會編譯錯誤。

13-3- 4 套件與存取控制的關係 在前面幾章中討論過存取控制字符與繼承的關係, 其中 protected 存取控制字符和套件息息相關, 我們在這裡做進一步的討論。 先回顧一下第 9 章所提過的存取控制字符。

套件與存取控制的關係 最外層的類別只能設為 public 或都不設 (預設存取控制), 千萬不可設為 protected 或private, 而且也不可設為 static, 否則會編譯錯誤。但內部類別則不受這些限制。

套件與存取控制的關係 由於存取控制字符可以加諸在成員、方法或是類別上, 因此必須特別小心。 舉例來說, 若類別的某個成員變數是 public, 但類別本身是預設存取控制, 則套件外部根本無法使用它, 自然也無法存取其 public 的成員變數, 請參考以下範例:

套件與存取控制的關係 DefaultClass 並未加上任何存取控制字符, 因此只有同一套件中的類別才能使用, 即使成員變數 i 是 public, 套件外的程式也無法存取。 在上一章中提到過, 介面預設就是 public, 所以不會有如上的問題。

套件與存取控制的關係 為了讓程式的用途明確清楚, 建議應為所有的類別以及成員、方法標示合適的存取控制字符, 基本的使用規範如下: 除非類別是要提供給套件外的其他類別使用, 否則請不要標示為 public。 如果成員或是方法只是提供給同一套件的其他類別使用, 而且允許衍生類別重新定義或是修改內容的話, 請將之標示為 protected。

套件與存取控制的關係 如果成員或是方法只是提供給同一套件的其他類別使用, 就不要標示存取控制字符, 採用預設存取控制。 如果成員或是方法只是提供給類別內的其他成員或是方法使用, 就請標示為 private。

13-3-5 預設套件 (Default Package) 還記得在 13-1 節中, 我們將幾何圖形的類別都單獨存放在單獨的檔案中, 回頭看一下各檔案的內容, 您可能會覺得奇怪:這些類別都沒有包裝在同一個套件中, 而且它們也都沒有加上存取控制字符。 依據上一小節的說明, 這些類別應該都只能給同一套件中的類別存取, 為什麼在主程式的 UsingOtherClasses 類別中可以直接使用這些類別, 而不會出現錯誤呢?

預設套件 (Default Package) 這是因為對目前資料夾中所有未標示套件的類別, Java 都會將之歸為預設套件 (Default Package) , 這個預設套件相當於一個沒有名字的套件。 所以在 UsingOtherClasses.java 程式中所用到同一資料夾中的其它類別, 就都屬於同一個預設套件, 所以程式可正常使用這些類別。 其實在前面幾章中將這些類別都放在同一個檔案中時, 也一樣是因為歸屬到同一個預設套件, 而可以相互使用。

13-3-6 Java 標準類別庫 事實上, Java 預設就提供了許多的套件, 可以幫助您處理多種工作。 例如 java.io 套件中就提供了許多輸出輸入的相關類別。 像是前幾章曾經使用到的 BufferedReader 與 InputStreamReader 就屬於此套件, 所以有些範例程式會在開頭 import java.io.*。

Java 標準類別庫 另外, java.lang 則提供了許多與 Java 語言本身有關的類別, 像是對應於基礎型別的 Integer 等類別, 就屬於此一套件。不過由於 Java 預設就會匯入 java.lang.*, 所以我們不需在程式中自行匯入。 從本書一開始就使用到的 System 就是 java.lang 套件中的類別, 它有 out 這個 static 的成員, 指向一個 java.io.PrintStream 物件, 因此我們才能呼叫 System.out.println( ) 方法將資料顯示在螢幕上。 有關 Java 本身提供的各類套件, 統稱為 Java 標準類別庫, 會在第 17 章做進一步的介紹

13- 4 套件的命名與打包 雖然套件可以防範類別名稱重複的問題, 但套件本身的名稱也可能會重複, 因此本節將介紹套件的命名慣例, 只要大家遵循此慣例, 就可避免名稱重複的問題。 另外, 我們寫好的程式或套件, 也可將其內容 (路徑結構及類別檔) 壓縮成 JAR 檔, 以方便傳遞或安裝使用;而其好處, 是在使用時可直接存取其內容, 就好像沒有壓縮一樣。

13-4-1 套件的命名慣例 雖然使用套件已經可以減少類別名稱重複的問題, 不過為了徹底解決這個問題, 一般來說, 套件的命名都會依循以下的規則, 避免套件名稱也發生衝突: 每家公司 (或是組織) 以其在網際網路上的網域名稱相反的順序為最上層套件的名稱, 例如旗標出版公司的網域名稱是 flag.com.tw, 因此, 只要是旗標所撰寫的類別, 都應該要放置在 tw.com.flag 這個套件中。

套件的命名慣例 如果需要的話, 可以再依據部門或是工作單位名稱, 在最上層套件中建立適當的子套件, 以放置該部門所撰寫的所有類別, 避免同一公司、不同單位的人使用相同的類別名稱。 在最上層套件中, 再依據類別的用途建立適當的子套件。舉例來說, 前面我們所建立的 flag.math 或是 flag.utility 子套件, 其實應該要建立為 tw.com.flag.math 以及 tw.com.flag.utility 套件才對。

套件的命名慣例 透過這樣的方式, 就可以確立不同單位所提供的套件, 其中的類別一定不會有重複的完整名稱。 如此一來, 即便不同單位的人寫了同樣名稱的類別, 但是冠上完整套件名稱時, 這兩個類別就不同名了。

13-4-2 將程式打包成 JAR 壓縮檔 當我們寫好程式之後, 可以將所有的類別 (含套件的路徑結構) 都包成JAR 壓縮檔, 以方便傳遞或安裝。 JAR (Java Archive) 檔是一種類似 ZIP 格式的壓縮檔, 副檔名為 .jar, 我們可使用 Java 提供的 jar.exe 來進行壓縮及解壓縮操作。 在示範 JAR 的操作之前, 我們先來準備要打包套件的路徑結構及類別檔, 請在書附範例的 Ch13\ 中執行以下命令:

將程式打包成 JAR 壓縮檔 此命令會編譯上一節寫好的 math 套件 (4 個形狀類別) 原始檔, 由於使用了 -d 13-4 參數, 所以會自動在 13-4\ 中建立套件的路徑 flag\math, 以存放編譯好的 4 個類別檔。 接著就來打包 JAR 檔, 請移到 13-4\ 中執行以下命令: 直接執行不加參數的 jar 命令, 即會顯示 jar 的使用說明。另外, 參數的 - 也可省略, 例如 -cf 也可寫成 cf。

將程式打包成 JAR 壓縮檔 如此就可建立好 flag.jar 檔了, 底下列出 jar 檔的內容:

將程式打包成 JAR 壓縮檔 在 JAR 檔中會維持套件的路徑結構, 並自動在 META-INF/ 子資料夾中加入一個 MANIFEST.MF 說明檔, 此檔可用來記錄版本編號、建立者、是否包含可執行的類別、以及執行時的 classpath 等資訊。 在一般狀況下可不用管它 (如果要修改, 則需遵循一定的格式)。

讓 JAR 檔可以直接執行 其實 JAR 檔不僅可用來打包套件, 甚至還可連要執行的類別一起打包, 那麼只要在 Windows 中雙按該 JAR 檔即可執行程式 (或執行 java -jar flag.jar 命令)。 假設我們在 13-4\ 中編譯好一個可執行的 App.class, 那麼就可用以下指令連 flag 套件一起打包:

讓 JAR 檔可以直接執行 以上 cfe 的 c 表示要建立 JAR 檔, f 表示接下來的參數為 JAR 的檔名, e 則表示再下一個參數為要執行的類別名稱。 而要加入 JAR 的資料夾 (或檔案) 則放在最後, 可以列出多個, 例如以上的 flag 資料夾及 App.class。建好 app.jar 之後, 就可以執行 java -jar app.jar 來測試了 (由於程式只有文字輸出, 若在 Windows 中雙按來執行, 則將看不到輸出的文字)。

將程式打包成 JAR 壓縮檔 當我們要使用 JAR 套件時, 同樣是用 -cp 參數來指定 JAR 檔即可, 例如在 Ch13\13-3\ 中執行上一節的 ImportPackage.java 程式: 以上 -cp 路徑中的 ".." 是代表上一層資料夾。而執行時的 -cp 參數中, 也要加上 ".;", 代表也要到目前路徑中尋找所需的類別檔 (ImportPackage.class 是放在目前路徑中)。

將程式打包成 JAR 壓縮檔 您可以把 flag.jar 想像成是一個虛擬資料夾, 因此 jar 檔內、外的路徑可以串接起來, 例如 13-4\flag.jar 就相當於 13-4\flag\math\*.class 。 千萬不可將 flag.jar 省略 (例如 -cp ..\13-4), 否則 Java 只會尋找 13-4\flag... 子資料夾, 而不會自動尋找 JAR 檔的內容。

將 JAR 套件加到系統類別庫中 如果打包好的 JAR 套件經常需要使用, 那麼也可將之放入 Java 的系統類別庫擴充路徑中:%JAVA_HOME%\jre\lib\ext。 其中的 %JAVA_HOME% 是指 Java 的安裝路徑, 例如 "C:\Program Files\Java\jdk1.6.0_11"。 在 SCJP 考試中, 有時會出現 $JAVA_HOME、JAVA_HOME 之類的字眼, 都是代表 Java 的安裝路徑。在 Windows 中如果設定了 JAVA_HOME="C:\Program..." 環境變數, 那麼就可在其他路徑中使用此變數, 例如 Java 程式檔所在的路徑可寫成 %JAVA_HOME%\bin。

將 JAR 套件加到系統類別庫中 如果要測試, 可將前面建立的 flag.jar 移到系統類別庫擴充路徑中, 然後將 Ch13\13-3 中的ImportPackage.java 單獨複製到上層資料夾 (以便與原路徑中的 flag 子資料夾分離), 再到 Ch13\ 中測試:

將 JAR 套件加到系統類別庫中 如果可以編譯但無法執行, 則通常是因為系統另外還安裝了 JRE (Java Runtime Environment) 版的 Java, 也就是只能執行程式而無編譯功能的版本。 此時還必須將 flag.jar 也複製到 JRE 安裝路徑 (例如 C:\Program Files\Java\jre6) 的 \lib\ext 中才行, 因為 java.exe 只會到此處尋找系統擴充類別。

13-4-3 編譯與執行時的參數設定 關於如何編譯與執行 Java 程式, 相信大家都已經很熟悉了, 本節再來補充一些實用的命令列參數。 底下是 javac.exe 常用的幾個參數。

編譯與執行時的參數設定

編譯與執行時的參數設定 底下則為 java.exe 的常用參數, 請注意 -D 參數和 javac.exe 的 -d 參數是不同的。

編譯與執行時的參數設定

編譯與執行時的參數設定 其中要特別說明的是 -D 參數。 Java 系統本身維護了一組系統參數(System Properties), 其中記錄了如作業系統名稱/版本、目前使用者的帳戶、系統的換行符號、暫存檔的路徑. . .等資訊。 而我們也可用 -D 參數來新增或修改系統屬性, 例如 -Dmy.name=Joy 則可新增一個名為 my.name 的系統屬性, 其值為 "Joy"。

編譯與執行時的參數設定 在程式中, 則可使用以下方法來取得特定的系統屬性值:

編譯與執行時的參數設定 其中 System.getProperti es() 會傳回所有系統屬性的值, 因此可再用 .getProperty() 來進一步取得特定屬性的值, 其結果與直接使用 System.getProperty() 相同。 若想列出所有的系統屬性, 則可執行以下程式:

13-A 加入新的類別到 flag 套件中

Given: Which class can access the variable fs? only in ZipFile class. any class extends ZipFile class. any class under the mytools package. any class in the mytools.util package. any class that has-a or is-a ZipFile class.

If class A extends class B, and class B is packed in My. jar If class A extends class B, and class B is packed in My.jar. Which statements will allow class A compiles? (Choose t hree . ) My.jar is located at /mytool/ and a classpath environment variable is set to include /mytool/My.jar.B. My.jar is located at /mytool/ and a classpath environment variable is set to include /mytool/My.jar. My.jar is located at /mytool/ and a classpath environment variable is set to include /mytool/My.jar.B.class.

My.jar is located at /mytool/ and the A class is compiled using javac -classpath /mytool/ A.java. My.jar is located at /mytool/ and the A class is compiled using javac -cp /mytool/My.jar A.java. My.jar is located at $JAVA_HOME/jre/lib/ext/. My.jar is located at $JAVA_HOME/jre/bin/. My.jar is located at $JAVA_HOME/jre/classes/.

Which code, inserted at line 3, will output "scjp" when excute "java -Dmy.pwd=scjp X"? args[0].substring(args[0].length()-4) B. System.getEnv("my.pwd") System.getProperty("my.pwd") System.getProperties("my.pwd") System.getProperties().getProperty("my.pwd")

The image represents the stucture of my package The image represents the stucture of my package. Please place the codes to the empty box that make Find class compiles .

Given: Which code inserted at line 4 in Drive class will compile? A. move(2);   B. Car.move(2);   C. tool.Car.move(2); D. import tool.Car; Car.move(2); E. Drive can't use the method in Car. F. super.tool.Car.move(2);

Given two files: Which code inserted at l ine 1 in second file will compile? A. import tool.*; B. import tool.Car.*; C. import static tool.*; D. import static tool.Car.move; E. import static tool.Car.move(); F. static import tool.*; G. static import tool.Car.*;

Given: This App.class locates in /work/my/image/apps and the CLASSPATH environment variable is set to " . " . Which two command lines will run App? (Choose all that apply. )

java App (if run from /work/). java App (if run from /work/my/image/apps/). java my.image.apps.App (if run from /work/). java my.image.apps.App (if run from /work/my/image/apps/). java -cp /work my.image.apps.App (if run from any directory). java -cp . App (if run from /work/my/image/apps/). java -cp /work/my/image/apps;. App (if run from /work/).