6.1 包:庫單元
控制對成員的訪問權(quán)限有兩個原因:
第一兆沙,為了使用戶不要碰觸那些他們不該碰觸的部分泥彤,這些部分對于類內(nèi)部的操作時必要的锯厢,但是他并不屬于客戶端程序員所需接口的一部分福扬。因此,將方法和域指定稱private梭姓,對客戶端程序員而言是一種服務(wù)。
第二嫩码,為了讓類庫設(shè)計者可以更改類的內(nèi)部工作方式,而不必擔(dān)心這樣會對客戶端程序員產(chǎn)生重大的影響罪既。
訪問權(quán)限控制專注于類庫創(chuàng)建者和該類庫的外部使用者之間的關(guān)系铸题,這種關(guān)系是一種通信方式。
訪問控制(或隱藏具體實現(xiàn))與"最初的實現(xiàn)并不恰當"有關(guān)琢感。換句話說就是:“我們的代碼幾乎不可能在一開始就做到最好丢间,后期的迭代可以逐步改善情況,訪問控制很大情況下就是為了后續(xù)代碼的改善”驹针。訪問權(quán)限控制的等級烘挫,從最大權(quán)限到最小權(quán)限依次為:public、protected柬甥、包訪問權(quán)限和private
import導(dǎo)入包饮六。一般都是import java.util.*;
每一個Java文件只能有一個public類。
6.1.1 代碼組織
當編譯一個.java文件的時候苛蒲,在.java文件中的每個類都會有一個輸出文件卤橄,而該輸出文件的名稱和.java文件中的每個類相同,多了個后綴名.class臂外。
Java可運行程序是一組可以打包并壓縮為一個Java文檔文件jar的.class文件窟扑。Java解釋器負責(zé)這些文件的查找、裝載和解釋漏健。
類庫實際上是一組類文件嚎货。其中每個文件都有一個public類,以及任意數(shù)量的非public類蔫浆。包的名稱對應(yīng)目錄路徑殖属。
package語句必須是文件中的第一行非注釋程序代碼。在一個項目中克懊,不可以有相同的兩個包名忱辅,也就是說,包名不能和項目中其他的包名重復(fù)谭溉,這里不但包括自定義包名也包括項目所引用的類庫的包名墙懂。
6.2 Java訪問權(quán)限修飾詞
對于一個類,其成員(包括成員變量和成員方法)能否被其他類所訪問扮念,取決于該成員的修飾詞损搬。在Java中,類成員的訪問權(quán)限修飾詞有四個:private,無(包訪問權(quán)限)巧勤,protected 和 public嵌灰。
所有事物都具備訪問權(quán)限控制,如果沒寫就是包訪問控制權(quán)限颅悉。這種默認的訪問權(quán)限沒有關(guān)鍵字沽瞭,有些時候表示為friendly。這就意味著當前的包中的所有其他類對那個成員都有訪問權(quán)限剩瓶,但對于這個包之外的所有類驹溃,這個成員是private的。
取得對某成員的訪問權(quán)限的唯一途徑:
使該成員成為public延曙;
通過不加訪問權(quán)限修飾符并將其他類放置于同一個包內(nèi)的方式給成員賦予包訪問控制權(quán)限豌鹤;
繼承而來的類可以訪問public和protected類,private類不行枝缔,只有兩個類處于同一個包時才能訪問默認權(quán)限的布疙;
提供訪問器和變異器,get和set方法愿卸。
特別地灵临,如果你不希望其他任何人對該類擁有訪問權(quán),你可以把所有的構(gòu)造器都指定為private的擦酌,從而阻止任何人創(chuàng)建該類的對象俱诸。這個時候,該類的對象就只能在其static成員內(nèi)部進行創(chuàng)建赊舶,這種情形有點像單例模式睁搭,例如像下面的例子那樣:
class Test {
? ? ? // private Constructor!
? ? ? private Test() {}
? ? ? // Allow creation via static method:
? ? ? public static Test getTest() {
? ? ? ? ? return new Test();
? ? ? }
? ? }
在上面所提到的四種修飾詞中,除 protected 外都很好理解和掌握笼平,在此略作簡述:
public :被public修飾的類成員能被所有的類直接訪問园骆;
private:被private修飾的類成員只能在定義它的類中被訪問,其他類都訪問不到寓调。特別地锌唾,我們一般建議將成員變量設(shè)為private的,并為外界提供 getter/setter 去對成員變量進行訪問夺英,這種做法充分體現(xiàn)了Java的封裝思想晌涕;
包訪問權(quán)限:包訪問權(quán)限就是Java中的默認的權(quán)限,具有包訪問權(quán)限的類成員只能被同一包中的類訪問痛悯。
protected關(guān)鍵字
===========================================================
被protected修飾的成員對于本包和其子類可見余黎。
實際上,protected的可見性在于兩點:
基類的protected成員是包內(nèi)可見的载萌,并且對子類可見惧财;
若子類與基類不在同一包中巡扇,那么在子類中,子類實例可以訪問其從基類繼承而來的protected方法垮衷,而不能訪問基類實例的protected方法厅翔。
在碰到涉及protected成員的調(diào)用時,首先要確定出該protected成員來自何方搀突,其可見性范圍是什么刀闷,然后就可以判斷出當前用法是否可行了仰迁。
===========================================================
//示例一package p1;
public class Father1 {
? ? protected void f() {}? ? // 父類Father1中的protected方法}package p1;
public class Son1 extends Father1 {}package p11;
public class Son11 extends Father1{}package p1;
public class Test1 {
? ? public static void main(String[] args) {
? ? ? ? Son1 son1 = new Son1();
? ? ? ? son1.f(); // Compile OK? ? ----(1)? ? ? ? son1.clone(); // Compile Error? ? ----(2)? ? ? ? Son11 son = new Son11();? ?
? ? ? ? son11.f(); // Compile OK? ? ----(3)? ? ? ? son11.clone(); // Compile Error? ? ----(4)? ? }
}
對于上面的示例涩赢,首先看(1)(3),其中的f()方法從類Father1繼承而來轩勘,其可見性是包p1及其子類Son1和Son11,而由于調(diào)用f()方法的類Test1所在的包也是p1怯邪,因此(1)(3)處編譯通過绊寻。其次看(2)(4),其中的clone()方法的可見性是java.lang包及其所有子類悬秉,對于語句“son1.clone();”和“son11.clone();”澄步,二者的clone()在類Son1、Son11中是可見的和泌,但對Test1是不可見的村缸,因此(1)(3)處編譯不通過。
===========================================================
//示例二package p2;class MyObject2 {
? ? protected Object clone() throws CloneNotSupportedException{
? ? ? return super.clone();
? ? }
}package p22;
public class Test2 extends MyObject2 {
? ? public static void main(String args[]) {
? ? ? MyObject2 obj = new MyObject2();
? ? ? obj.clone(); // Compile Error? ? ? ? ----(1)? ? ? Test2 tobj = new Test2();
? ? ? tobj.clone(); // Complie OK? ? ? ? ----(2)? ? }
}
對于(1)而言武氓,clone()方法來自于類MyObject2本身梯皿,因此其可見性為包p2及MyObject2的子類,雖然Test2是MyObject2的子類县恕,但在Test2中不能訪問基類MyObject2的protected方法clone()东羹,因此編譯不通過;對于(2)而言,由于在Test2中訪問的是其本身實例的從基類MyObject2繼承來的的clone()忠烛,因此編譯通過属提。
===========================================================
//示例三package p3;class MyObject3 extends Test3 {
}package p33;
public class Test3 {
? public static void main(String args[]) {
? ? MyObject3 obj = new MyObject3();
? ? obj.clone();? // Compile OK? ? ------(1)? }
}
對于(1)而言,clone()方法來自于類Test3美尸,因此其可見性為包p33及其子類MyObject3冤议,而(1)正是在p33的類Test3中調(diào)用,屬于同一包师坎,編譯通過恕酸。
===========================================================
//示例四package p4;class MyObject4 extends Test4 {
? protected Object clone() throws CloneNotSupportedException {
? ? return super.clone();
? }
}package p44;
public class Test4 {
? public static void main(String args[]) {
? ? MyObject4 obj = new MyObject4();
? ? obj.clone(); // Compile Error? ? ? -----(1)? }
}對于(1)而言,clone()方法來自于類MyObject4屹耐,因此其可見性為包p4及其子類(此處沒有子類)尸疆,而類Test4卻在包p44中椿猎,因此不滿足可見性,編譯不通過寿弱。
==========================================================//示例五package p5;class MyObject5 {
? ? protected Object clone() throws CloneNotSupportedException{
? ? ? return super.clone();
? ? }
}
public class Test5 {
? ? public static void main(String[] args) throws CloneNotSupportedException {
? ? ? MyObject5 obj = new MyObject5();
? ? ? obj.clone(); // Compile OK? ? ? ? ----(1)? ? }
}對于(1)而言犯眠,clone()方法來自于類MyObject5,因此其可見性為包p5及其子類(此處沒有子類)症革,而類Test5也在包p5中筐咧,因此滿足可見性,編譯通過噪矛。
===========================================================//示例六package p6;class MyObject6 extends Test6{}
public class Test6 {
? public static void main(String[] args) {
? ? MyObject6 obj = new MyObject6();
? ? obj.clone();? ? ? ? // Compile OK? -------(1)? }
}對于(1)而言量蕊,clone()方法來自于類Test6,因此其可見性為包p6及其子類MyObject6艇挨,而類Test6也在包p6中残炮,因此滿足可見性,編譯通過缩滨。
===========================================================//示例七package p7;class MyObject7 extends Test7 {
? ? public static void main(String[] args) {
? ? ? ? Test7 test = new Test7();
? ? ? ? test.clone(); // Compile Error? ----- (1)? }
}
public class Test7 {
}對于(1)而言势就,clone()方法來自于類Object,因此該clone()方法可見性為包java.lang及其子類Test7脉漏,由于類MyObject7不在此范圍內(nèi)苞冯,因此不滿足可見性,編譯不通過侧巨。
6.3 接口與實現(xiàn)
訪問權(quán)限的控制常被稱為是具體實現(xiàn)的隱藏舅锄。把數(shù)據(jù)和方法包裝進類中,具體實現(xiàn)的隱藏司忱,常共同被稱作是封裝皇忿。其結(jié)果是一個同時帶有特征和行為的數(shù)據(jù)類型。
6.4 類的訪問權(quán)限
每個編譯單元(文件)都只能有一個public類烘贴,特殊情況下可以沒有禁添。
public類的名稱必須完全與含有該編譯單元的文件名一模一樣。