另類的package-info.java檔案探討 [轉]
翻看以前的筆記,看到一個特殊的java檔案:pacakge-info.java,雖然有記錄,但是不全,就嘗試著追蹤一下該問題,分享一下流水賬式的結果。
首先,它不能隨便被建立。在Eclipse中, package-info檔案不能隨便被建立,會報“Type name is notvalid”錯誤,類名無效,Java變數定義規範是:字母、數字、下劃線,還有那個不怎麼常用的$符號(順帶說下,Java是支援中文名稱的變數,習慣挑戰的同學可以嘗試下,分享一下這方面的經驗),這個中劃線可不再之列,那怎麼建立這個檔案呢?
很簡單,用記事本建立一個,然後拷貝進去再改一下就成了,更直接的辦法就是從別的專案中拷貝過來一個,這更方便。
其次,服務的物件很特殊。一個類是一類或一組事物的描述,比如Dog這個類,就是描述旺財的,那package-info這個類是描述啥的呢?它總要有一個被描述或被陳述的物件,它是描述和記錄本包資訊。
最後,類不能帶有public、private訪問許可權。package-info.java再怎麼特殊,也是一個類檔案,也會被編譯成package-info.class,但是在package-info.java中只能宣告預設訪問許可權的類,也就是友好類。
其實還有幾個特殊的地方,比如不可以繼承,沒有介面,沒有類間關係(關聯、組合、聚合等等)等。
這個檔案的特殊性說完了,那再說說它有什麼作用,它有三個作用:
1、為標註在包上Annotation提供便利;
2、宣告友好類和包常量;
3、提供包的整體註釋說明。
我們來建立一個專案演示這三個作用,建立一個package-info的Java Project,在com.company包三個類:package-info.java 是我們重點關注的,PkgAnnotation.java是一個標註在包上的註解定義,Client.java模擬業務操作類。其結構如下圖:
為標註在包上Annotation提供便利
首先定義一個包型別的註解,它只能放置的一個包上:
Java程式碼- /**
- * 定義只能標註在package上的註解
- */
- @Target(ElementType.PACKAGE)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface PkgAnnotation {
- }
/** * 定義只能標註在package上的註解 */ @Target(ElementType.PACKAGE) @Retention(RetentionPolicy.RUNTIME) public @interface PkgAnnotation { }
再定義一個package-info類,這個是一個特殊的類,先看程式碼:
Java程式碼- @PkgAnnotation
- package com.company;
@PkgAnnotation package com.company;
很簡單,就這麼個檔案,裡面啥都沒有,就這兩句話,沒有class類,沒有常變數宣告。接著寫一個模擬交易類,程式碼如下:
Java程式碼- public class Client {
- public static void main(String[] args) {
- //可以通過I/O操作或配置項獲得包名
- String pkgName = "com.company";
- Package pkg = Package.getPackage(pkgName);
- //獲得包上的註解
- Annotation[] annotations = pkg.getAnnotations();
- //遍歷註解陣列
- for(Annotation an:annotations){
- if(an instanceof PkgAnnotation){
- System.out.println("Hi,I'm the PkgAnnotation ,which is be placed on package!");
- /*
- * 註解操作
- * MyAnnotation myAnn = (PkgAnnotation)an;
- * 還可以操作該註解包下的所有類,比如初始化,檢查等等
- * 類似Struts的@Namespace,可以放到包名上,標明一個包的namespace路徑
- */
- }
- }
- }
- }
public class Client { public static void main(String[] args) { //可以通過I/O操作或配置項獲得包名 String pkgName = "com.company"; Package pkg = Package.getPackage(pkgName); //獲得包上的註解 Annotation[] annotations = pkg.getAnnotations(); //遍歷註解陣列 for(Annotation an:annotations){ if(an instanceof PkgAnnotation){ System.out.println("Hi,I'm the PkgAnnotation ,which is be placed on package!"); /* * 註解操作 * MyAnnotation myAnn = (PkgAnnotation)an; * 還可以操作該註解包下的所有類,比如初始化,檢查等等 * 類似Struts的@Namespace,可以放到包名上,標明一個包的namespace路徑 */ } } } }
執行結果如下所示:
Hi,I'm the PkgAnnotation ,which is be placed on package! |
宣告友好類和包常量
這個比較簡單,而且很實用,比如一個包中有很多的內部訪問的類或常量,就可以統一的放到package-info類中,這樣就方便,而且集中管理,減少friendly類到處遊走的情況,看例子:
Java程式碼- @PkgAnnotation
- package com.company;
- //這裡是包類,宣告一個包使用的公共類,強調的是包訪問許可權
- class PkgClass{
- public void test(){
- }
- }
- //包常量,只執行包內訪問,適用於分“包”開發
- class PkgConst{
- static final String PACAKGE_CONST="ABC";
- }
@PkgAnnotation package com.company; //這裡是包類,宣告一個包使用的公共類,強調的是包訪問許可權 class PkgClass{ public void test(){ } } //包常量,只執行包內訪問,適用於分“包”開發 class PkgConst{ static final String PACAKGE_CONST="ABC"; }
提供包的整體註釋說明
如果是分“包”開發,也就是說一個包實現一個業務邏輯或功能點、或模組、或元件,則需要對一個包有很好的說明,說明這個包是幹啥的,有啥作用,版本變遷,特別說明等等,如下:
Java程式碼- /**
- * <b>package-info不是平常類,其作用有三個:</b><br>
- * 1、為標註在包上Annotation提供便利;<br>
- * 2、宣告包的私有類和常量;<br>
- * 3、提供包的整體註釋說明。<br>
- */
- package com.company;
/** * <b>package-info不是平常類,其作用有三個:</b><br> * 1、為標註在包上Annotation提供便利;<br> * 2、宣告包的私有類和常量;<br> * 3、提供包的整體註釋說明。<br> */ package com.company;
通過javadoc生成的API文件如下:
這與包下放置package.htm沒啥區別,只是package-info可以更好的在程式碼中維護文件的完整性,並且可以實現程式碼與文件同步更新,package.htm也可以做到,不爭論,建議是Java 1.5以上版本都使用package-info.java來註釋。
與package-info相關的問題
在專案開發中,可以放置在包上的常用註解有:Struts的@namespace、Hibernate的@FilterDef和@TypeDef等等。在包下,隨便一個類中的包名前加這些註解,Eclipse會提示“Package annotations must be in file package-info.java”,在該包下建立package-info.java檔案,把註解移到這裡即可。
使用Checkstyle外掛做程式碼檢查時,會報一個警告“Missing package-info.java file.”也是這個package-info檔案惹的禍,在各個包下建立一個即可。