一区二区三区在线-一区二区三区亚洲视频-一区二区三区亚洲-一区二区三区午夜-一区二区三区四区在线视频-一区二区三区四区在线免费观看

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|JAVA教程|ASP教程|

服務器之家 - 編程語言 - JAVA教程 - 深入解讀Java代碼組織中的package包結構

深入解讀Java代碼組織中的package包結構

2020-04-10 15:29vang JAVA教程

這篇文章主要介紹了Java代碼組織中的package包結構,是Java入門學習中的基礎知識,需要的朋友可以參考下

如果我們在Class對象上調用getPackage方法,就可以得到描述該類所在包的Package對象(Package類是在java.lang中定義的)。我們也可以用包名通過調用靜態方法getPackage或者調用靜態方法getPackages(該方法返回由系統中所有已知包構成的數組)來獲得Package對象。getName方法可以返回包的全名。

  Package對象的使用與其他反射類型完全不同,即我們不能在運行時創建或操縱包。我們可以使用Package對象來獲取有關包的信息,諸如包的用途、誰創建了包、包的版本等。我們將把這些內容延后到后面詳細介紹包時再討論。

包的命名
包的名字應該避免與其他包沖突,所以選擇一個既有意義又唯一的名字是包設計的一個重要方面。但是全球的程序員都在開發包,根本就沒有辦法獲知誰采用了什么包名,因此選擇唯一的包名是一個難題。如果我們確定某個包只在我們的組織內部使用,那么我們就可以讓內部仲裁者(internal arbiter)來確保項目之間不會發生名字沖突。

  但是對于整個世界而言,這種方法是不實際的。包的標識符都是簡單的名字,一種比較好的能夠確保包名唯一的方法是使用Internet域名。如果我們所就職的公司的名字為Magic.lnc,該公司的域名為magi c.com,那么屬性包的聲明就應該是:

  

?
1
package com.magic.attr;

注意,這里的域名構成元素是按常規域名的倒序排列的。

  如果我們采用這種慣用法,那么除了在我們的組織內部可能會產生沖突外,我們所采用的包名就不會與其他任何人的包名沖突了。如果我們的組織內部確實產生了沖突(可能是大型的企業),那么我們可以使用更具體的域名來進一步限定。許多大型公司都有內部子域名,如east和europe,可以使用這樣的子域名來進一步限定包的名字:

?
1
package corn. magic.japan.attr;

  使用這種方案可能會使包的名字變得很長,但是相對比較安全。使用這種技巧的程序員不會選擇相同的包名,而不使用這種技巧的程序員也不會選擇我們所采用的名字。

包的內容
包的內容應該仔細設計,使其只包含在功能上相關的類和接口。包中的類可以自由地訪問該包中其他類的非私有成員,有些類甚至可能有足夠的權限去訪問其他類的內部細節,為了避免這樣的類對類成員進行誤操作,我們需要對類成員進行保護。任何沒有被聲明為private的成員都可以被同一個包中的其他所有類型訪問,所以任何不相關的類之間的藕合程度都可能會比我們所期望的程度高。

  包還為尋找有用的接口和類的程序員提供了邏輯分組的功能。由不相關的類組成的包使程序員很難分辨出哪些接口和類是有用的,而類的邏輯分組可以幫助程序員重用代碼,因為程序員通過邏輯分組能夠更容易地找到他們所需要的東西。如果包中只包含相關的、緊藕合的類型集,則意味著我們可以給類型取一些更直觀的名字,從而避免名字沖突。

  包可以嵌套。例如,java.lang就是一個嵌套包,其中,包Lang嵌套在更大的包java中,而包j ava卻還包含一些其他的包。嵌套使得相關的包構成了具有層次結構的命名系統。

  例如,為了創建一組包,用于諸如神經網絡和遺傳算法這樣的自適應系統,我們可以用以圓點分隔的名字來命名包,從而創建嵌套包:

?
1
package adaptive. neural Net;

  含有上面這條聲明語句的源文件位于adaptive.neuralNet包中,而adaptive.neuralNet包本身又是adaptive包的子包。adaptive包中可能包含一些與通用的自適應算法相關的類,例如泛化問題陳述類或基準測試類。在層次結構中處于更深位置的包(例如adaptive. neu-ralNet或adaptive.genetic)包含與特定類型的自適應算法相關的類。

  包的嵌套僅僅是組織相關包的一種工具,它并不能提供包之間的任何特殊的訪問權限。

  adaptive.genetic包中的類代碼無法訪問adaptive或adaptive.neuralNet包中具有包訪問權限的成員,包作用域只適用于特定的包。包的嵌套可以對相關的包進行分組,并幫助程序員更方便地在邏輯層次中找到想要的類,但是除此之外,它并未帶來其他的任何益處。

包的注解

  包也可以有注解。但是問題在于,由于包是一種組織結構,沒有源代碼實體,它們并沒有實際的定義,所以不能像對類或方法那樣對它們進行注解,因此包的注解只能通過在源文件中對包的聲明語句進行注解來實現。然而,在每個包中只能有一個包聲明可以擁有作用于它的注解。

  那么究竟如何對包進行注解呢?事實上,Java語言并沒有強制程序員必須使用某種方式來處理“單一注解的包語句”規則。所建議的方式是在包目錄中創建一個名為package一i nfo.java的文件,在這個文件中只存儲包語句和該包的注解,而不放置任何其他內容。例如,用于attr包的package一info.java文件看起來就是這樣的:

?
1
2
3
4
5
6
7
@PackageSpec(name二”Attr Project",version="1.0"
 
@DevelopmentSite("attr.project.org")
 
@DevelopmentModel("open一source")
 
package attr;

  其中Packagespec,Developmentsite和Devel opmentmodel用來修飾注解類型,當然,它們具有運行時的保存策略。package一info.java文件應該和包中的其他源文件一起編譯。

  我們推薦將所有與包相關的信息都放置在package一info. java文件中。如果你這樣做了,那么你就可以在文件的開頭放置文檔注釋,從而使這些文檔被注釋成包文檔。

包的訪問
在聲明包中的頂層類和頂層接口的可訪問性時,有兩種選擇:包訪問權限(package)和公共訪問權限(public)。用public修飾的類或接口可以被包外的代碼所訪問,而沒有用public修飾的類型則具有包作用域:它們可以被同一個包中的其他代碼所訪問;但對于包外的代碼,甚至是子包中的代碼,它們都是隱藏的。我們在聲明類型時,應該只把其他程序員需要使用的那些類型聲明為public的,而隱藏那些屬于包的實現細節的類型。這種技術給我們提供了極大的靈活性,由于程序員并不依賴于這些他們所不能訪問的實現細節的類型,所以當我們想改變實現細節時,可以自由地改變它們。

  沒有被聲明為public,protected或private的類成員可以被包內的任何代碼直接訪問,但對包外的代碼是隱藏的。換句話說,默認的訪問修飾符是“package",但接口的成員例外,它們的默認訪問修飾符是“public" .

  在包內沒有聲明為private的字段或方法可以被該包中的所有其他代碼所訪問,因此,同一個包中的類都被認為是“友好的”或“可以信任的”。這樣就使得我們可以定義組合了預定代碼(predefined code)和占位符代碼(placeholder code)的應用框架,其中占位符代碼被框架類的子類覆蓋。預定義代碼可以使用包訪問權限修飾符,這樣包內的其他相互協作的代碼就可以直接訪問它們,但對于包外用戶,這些代碼是不可訪問的。然而,這些代碼所在包的子包是不被信任的,反之亦然。例如,在包dit中用包訪問權限修飾符修飾的代碼不能被其子包dit.dat中的代碼所訪問,反之亦然。

  因此,每種類型都定義了三種不同的契約:

  .publi。契約:定義了類型的主要功能。

  .protected契約:定義了子類可獲得的用于特化目的的功能。

  .package契約:定義了包內其他代碼可獲得的用來實現包內類型之間協作的功能。所有這些契約都需要仔細考慮和設計。

  可訪問性和及蓋方法

  只有在超類中可以訪問到的方法才可以在子類中被覆蓋。如果超類中的某個方法不能被訪問,那么即使子類中的方法與該方法同名,在子類中也不能覆蓋該方法。當某個方法在運行時被調用時,系統會考慮它的可訪問性,從而決定運行它的哪一個具體實現。

  下面這個特意構建的例子解釋得更加清楚。假設我們在P1包中聲明了一個Abstract-Base類:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
  package P1;
 
  { Ab Ab AbAb
 
     public abstract class AbstractBase
 
     private void pri()
 {
     print( " stractBase.pri()”):} void pac () {print(" stractBase.pac() ” );
 }
 
 
     protected void pro()
 {
     print( " stractBase.pro()" );
 }
 
 
     public void pub()
 {
     print (" stractBase.pub()”);}
 
public final void show()
 
pri();
 
pac();
 
pro();
 
pub();
 
}
 
}

  在這個類中,我們定義了4個方法,每個方法都具有不同的訪問權限修飾符,且方法體都只是標識其自身。方法show在當前對象上依次調用了這4個方法,當把該方法應用于不同的子類對象時,就可以說明到底調用了這些方法的哪個實現。

  現在,我們定義類Concretel,這個類擴展了AbstractBase類,但是位于P2包中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package P2;
 
import P1.AbstractBase
 
public class Concretel extends AbstractBase{
 
public void pri(){print("Concretel.pri()”);}
 
public void pac(){print("Concretel.pac()”);}
 
public void pro(){print("Concretel.pro()”);}
 
public void pub(){print("Concretel.pub()");}
 
}

  在該類中重新聲明了超類中的4個方法,并改變了它們的實現,這些實現在報告它們屬于Con-cretel類。同時,它們的訪問權限都被改成了public,以便其他代碼訪問。執行下面的代碼

?
1
new Concretel().show():

  將產生如下輸出:

?
1
2
3
4
5
6
7
AbstractBase.pri()
 
AbstractBase.pac()
 
Concretel.pro()
 
Concretel.pub ()

  因為私有方法pri不能被子類(或其他類)所訪問,所以show方法總是調用AbstractBase類中的pri方法的實現。AbstractBase類中的具有包訪問權限的pac方法不能被Concretel訪問,因此Concretel類中的pac方法的實現不能覆蓋AbstractBase類中的定義,故show方法調用的是AbstractBase.pac方法。pro方法和pub方法在Concretel類中都是可以訪問的,同時也可以被覆蓋,所以show方法中調用的是Concretel類中的這兩個方法的實現。

  接卜采我們足義類Concrete2,來擴展類Concretel,然后我們把它和AbstractBase類放到同一個包P1中':

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package P1;
 
import P2.Concretel
 
public class Concrete2 extends Concretel{
 
public void pri(){print("Concrete2.pri()”);}
 
public void pac(){print("Concrete2.pac ()”);}
 
public void pro(){print("Concrete2.pro()”);}
 
public void pub(){print("Concrete2.pub()");}
 
}

  因為Concretel中的方法都具有public訪問權限,所以在Concrete2中都可以訪問到,而且Concrete2中的每一個方法分別對其相應的方法進行了覆蓋。此外,因為Concrete2和Ab-stractBase在同一個包中,所以在Concrete2中也可以訪問到方法AbstractBase.pac,并且可以覆蓋方法Concrete2.pac。在Concrete2對象上調用show方法,打印結果如下:

?
1
2
3
4
5
6
7
AbstractBase.pri()
 
Concrete2.pac()
 
Concrete2 .pro()
 
Concrete2.pub()

  最后,我們定義類Concrete3來擴展類Concrete2,并放在包P3中:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
package P3
 
import P1.Concrete2;
 
public class Concrete3 extends Concrete2{
 
public void pri(){print("Concrete3.pri()”);}
 
public void pac Q{print("Concrete3.pac()”);}
 
public void pro(){print("Concrete3.pro()”);}
 
public void pub(){print("Concrete3.pub()”);}
 
}

  在Concrete3對象上調用show方法,打印結果如下:

?
1
2
3
4
5
6
7
AbstractBase.pri()
 
Concrete3.pac ()
 
Concrete3.pro()
 
Concrete3.pub()

  在這里方法Concrete3.pac看起來是覆蓋了不可訪問的AbstractBase.pac方法,但實際上是,方法Concrete3.pac覆蓋了方法Concrete2.pac,而方法Concrete2.pac覆蓋了方法AbstractBase.pac,因此方法Concrete3.pac間接地覆蓋了方法AbstractBase.pac。通過在類Concrete2中重新把pac方法聲明為具有public訪問權限,可以使其能夠被任何子類所訪問和覆蓋。


包對象和規范

包通常會實現某種規范,并且通常是來自于某個組織的。Package對象與其他的反射類型不同,不能用來創建或操作包,而只能充當提供信息的知識庫,用來提供有關包所實現的規范的信息(規范的標題、供應商和版本號)和有關包的實現本身的信息(包的標題、供應商和版本號)。雖然包通常來自于單個的組織,但它所實現的規范(如統計分析庫)卻可能是其他組織已定義過的。使用包的程序可能需要知道該包所實現的規范的版本,從而可以使用只在某個版本中定義的功能。類似地,這些程序還可能需要知道提供給它的是哪個實現版本,這主要是為了處理在不同版本中可能存在的缺陷。Package類的一些主要方法允許訪問到這些信息:

  ·public Stri ng getName ():返回該包的名字。

  .public string getspecificationTitle p:返回該包所實現的規范的標題,如果標題未知,則返回null,

  .public string getspecificationversion():返回一個描述該包所實現的規范的版本信息的字符串,如果版本信息未知,則返回null,

  .public string getspecificationvendor Q:返回供應商的名字,這個供應商擁有并維護該包所實現的規范,如果供應商未知,則返回null,

  .public string getImplerentationTitle():返回該包所提供的實現的標題,如果標題未知,則返回null, ·public string getImplementationversion():返回一個描述該包所提供的實現的版本信息的字符串,如果版本信息未知,則返回null,

  ·public string getImplementationvendor():返回提供該實現的組織(供應商)的名字,如果該組織未知,則返回null,

  例如,在我們的系統中提取java.lang包的這些信息,將會得到如下結果:

?
1
2
3
4
5
6
7
8
9
10
11
Specification Title: Java Platform API Specification
 
Specification Version: 1.4
 
Specification Vendor:Sun Microsystems,Inc.
 
Implementation Title:Java Runtime Environment
 
Implementation Version:1.5.0_02
 
Implementation Vendor: Sun Microsystems,Inc.

  規范版本號由句點分隔符分開的非負數字組成,如‘'2.0'‘或”11.0.12"。這種模式使得我們可以調用iscompatiblewith方法對遵循該模式的版本號與包的版本號進行比較。如果包的版本號大于等于傳人的版本號,那么該方法就返回true。這種比較每次只比較一個由句點分隔的數字,如果這些數字中任何一個小于傳遞進來的版本號中對應位置的值,那么這兩個版本就不兼容。如果其中一個版本號比另一個長,那么在短的版本號中缺少的部分將被認為是零。例如,如果包的規范版本號是”1.4",并且我們用iscompatiblewith方法將其與”1.2","1.3.1'.或”.1.81.進行比較時,那么將返回true;但是如果與''1.4.2'.或”.5"進行比較,那么將返回false。之所以得出這樣的結論,是因為這種比較機制假設規范版本是向后兼容的。

  實現的版本號沒有規定的格式,因為提供實現的不同組織會對實現版本做不同的定義。在實現版本之間唯一能做的比較是測試版本是否相同,其中沒有向下兼容的假設。

  包可以被密封起來,這意味著不能再向這個包中添加類了。未密封的包可以包含來自類搜索路徑中多個不同位置的類,而被密封的包的內容必須來自相同的位置—要么是某個特定的歸檔文件,要么是由某個URL指定的位置。有兩種方法可以確定一個包是否被密封了:

  .public boolean issealed p:如果該包被密封了,則返回trueo

  .public boolean issealed(URL url):如果該包對于給定的URL是密封的,則返回true,也就是說,該包中的類可以從這個給定的URL處加載。如果包中的類不能從給定的URL加載,或者包沒有被密封,則返回false,包的規范和實現信息通常是作為與包存儲在一起的清單文件的一部分而提供的—例如作為Java歸檔文件(jar)中的清單文件的一部分,就像25.9.2節“歸檔文件java.util.jar”中描述的那樣。當加載包中類時,這些信息就會被讀人。類加載器(ClassLoader)可以為它要加載的類動態地定義一個Package對象:

  .protected Package de臺nePackage (String name,string specTitle,Stringspecversion,string specvendor, String implTitle,string implversion,string implvendor, uRL sealBase):該方法將返回一個Package對象,該對象具有給定的包名和由相應的引元設置的規范和實現值。如果參數sealBase為null,那么這個包就是沒有密封的,否則包對于這個URL就是密封的:類的Package對象必須要在該類被定義之前定義,并且包的名字在類加載器中必須是唯一的。如果包名與現有名字重復,就會拋出工11ega1ArgumentException異常。

  我們可以調用給定類的Class對象的getPackage方法來獲得這個類的Package對象。我們也可以用給定的包名調用靜態方Package.getPackage來獲得Package對象,或者調用靜態方Package.getPackages,它將返回由類加載器當前已知的所有包組成Package數組。這兩個方法都與調用它們的代碼的類加載器有關,因為這些代碼將調用其類加載器的get-Package或getPackages方法。這些類加載器的方法將搜索特定的類加載器及其所有父類加載器,如果對當前類加載器沒有做任何設置,那么此時就會使用系統類加載器。請注意,如果包未知,那么類加載器方法將返回null,因為此時還沒有加載包中的任何類型。

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 国产清纯女高中生在线观看 | 亚洲va国产日韩欧美精品色婷婷 | 大肥婆丰满大肥奶bbw肥 | 日韩高清无砖砖区2022 | 男人狂躁女人下半身 | 成人性生交大片免费看软件 | 四虎影视884aa·com | 四虎影院新网址 | 国产成人高清精品免费5388密 | 99视频久久精品久久 | 成人一区二区丝袜美腿 | 9久热久爱免费精品视频在线观看 | 91免费在线播放 | 体检小说 | 午夜亚洲国产 | 狠狠久久久久综合网 | 国产精品99久久免费观看 | 二区免费视频 | bdsm中国精品调教 | 美女脱了内裤打开腿让人羞羞软件 | 久久精品热在线观看30 | 变态 调教 视频 国产九色 | 日韩一区二区三区在线 | a级毛片毛片免费很很综合 a级黄色视屏 | 男人的私人影院 | 色碰视频| 香蕉精品国产高清自在自线 | 我要看逼 | 国产精品对白刺激久久久 | 91日本在线| 四虎影视在线观看2413 | bl双性肉文| 国语视频高清在线观看 | miaa076深田咏美在线 | 国产精品久久久久久久久免费 | 亚洲欧美国产另类视频 | 亚洲欧美日韩一区成人 | 国产成人精品一区二区仙踪林 | 小妇人电影免费完整观看2021 | 91久久福利国产成人精品 | 日本护士xxxx爽爽爽 |