第五章 隱藏實現細目
首先考慮oop的一個重要思想--讓變動的東西和不變動的事物彼此分開。
java庫的程式員在編寫庫的時候最需要考慮到的就是,一旦他們改變類中的某個函數或者是成員變數,讓已經使用前一版本庫的程式不會受到變動的影響。庫的編寫者無法知道程式員調用用了庫中那些函數和變數,因而無法修改庫的成員,於是為瞭解決這樣的問題,java中出現了存取控制符,其作用就是告訴程式員,那些是可用的,那些是停用,而java中的存取控制符是受package(包)的影響的,因此,在學習存取控制符以前,先要學習好包。
package:程式庫單元
現在大家想象一下這種情況,假如你現在本地開發了一套java程式,現在把他投入使用,當你把程式放到伺服器上的時候,也許你會發現,伺服器上的原有的class和你現在程式中的class重名了!怎麼解決呢?這個時候就需要java中的命名空間了。正是因為有了命名空間,使得名稱相同的class各自存活在各自的相對領域中,互不干擾,當你需要調用不同命名空間內的class時,使用import關鍵字,例如:調用整個程式庫import java.util.*;這樣就是在調用一個包,如果你想調用其中的一個類,這樣import java.util.math;
如何設定自己的包?使用package xxx ;放在程式的最前面,就是把該程式收錄到xxx包中,使用的時候,只要import xxx就可以了。關鍵字import和package提供的是,無論多少人撰寫class,永遠不會發生命名衝突!
獨一無二的package命名
package應該把所有隸屬於同一個package的class放置在同一個目錄中,或者使用jar。那麼現在又出現2個問題:如何產生獨一無二的package名,並且如何找出深藏在檔案目錄中class。我們一般使用反轉的國際網域名稱來保障問題1的正確解決,我的網域名稱是blog.csdn.com/maoerzuozuo,於是我使用maoerzuozuo.com.csdn.blog來命名包,這樣我就能產生和其他人不重複的package名稱(除非他把我的東西搶先使用)。第2個問題通過環境變數中的classpath解決,classpath含有一個或者多個目錄,每個目錄看成class檔案的尋找起點,把你的包名稱轉換成磁碟目錄進行尋找
package maoerzuozuo.com.csdn.blog.test;
public class demo
{
public demo()
{
System.out.println("maoerzuozuo.com.csdn.blog.test.demo");
}
}
調用
import maoerzuozuo.com.csdn.blog.test.*;
public class test
{
public static void main(String args[])
{
demo d= new demo();
}
}
我們把2檔案儲存體在f:/maoerzuozuo/com/csdn/blog/test/下,接著我們調用他,並且設定環境變數classpath=.;f:/; 於是程式正常運行,編譯器能找到我調用的包,並且能正常運行。注意:你需要調用的class必須是public的!
衝突
假如我調用了2個包,但是2個包中都有test類,當我執行個體化test類時候,你必須告訴編譯器你執行個體化的是哪個包中的class,否則就會引起衝突
例如 java.util.Date d= new java.util.Date();
自定一個程式庫
現在,我們可以定義屬於自己的程式庫,方便自己的使用,這裡我們定義一個輸出類,用來方便我們程式使用.我們現在來寫一個顯示類
package maoerzuozuo.com.csdn.blog.test;
public class show
{
public static void go(String s)
{
System.out.println(s);
}
}
我們把他存放在F:/maoerzuozuo/com/csdn/blog/test 下,並且在環境變數的下classpath做好指向,現在來使用
import maoerzuozuo.com.csdn.blog.test.show;
class test
{
public static void main(String args[])
{
show.go("hello");
}
}
但是請注意,當我們調用show.go(123);的時候,go()函數沒辦法像System.out.println();一樣把int自動進行轉化為string
使用package的一些忠告
當你是使用package的時候,其實你也就是間接的指定了實際的系統目錄結構,因此,你的class必須位於這個目錄之中,並且系統會從classpath開始,查詢到該目錄。
java存取權限控制詞
java中,對類、函數、成員資料都會有存取控制符,他們依次為public 、private、protected 和 friendly(無存取控制符)4種,我記得我當時培訓的時候,我的老師告訴我"public 是公用的,private是私房錢 protected是大熊貓"
friendly(友好的)
當在類、函數、成員資料前不寫任何存取控制符的時候,就是friendly,他的意義就是在同一個包中,所有的class都可以訪問,或者當你沒有定義任何的包的時候,只要在同一個目錄內的檔案也是可以互相訪問的,編譯器會視他們為一個包,但是對於包外的class形同private,也可以稱做package存取權限
public (公用的)
關鍵字public代表任何人都可以訪問他
private(私房錢)
先想想私房錢的概念,私房錢只所以這麼叫,是因為這個錢只有本人自己才能使用。所以private代表的意思就是說除了class本身,沒有誰再能訪問他了。private充分體現了封裝性
protected(大熊貓)
大熊貓是受到保護的,並且他的子女因為繼承大熊貓的關係也是受到保護的,所以protected的意義在於允許衍生類別訪問基類的成員,而基類的包中的其他類也是可以訪問的(friendly)
interface(介面) and implemention(實現)
實現細節的隱藏通常使用存取控制符來實現,他可以把class內的資料根據不同的需要封裝起來,讓特定的人訪問,建立不同的訪問界限
通常我們在2種情況下需要使用存取控制符
1、告訴二次開發的程式員,那些是可用的,那些是停用,從而當我們更改 相關資料時,不會影響到其他的人原有的程式。
2、將介面和實現分離,一般用戶端程式員使用的是該類的介面,而具體的實現過程沒有必要讓程式員知道,我們可以將他封裝起來。這樣,我們可以把介面聲明為公用的,而內部的實現過程可以根據實際的需要,聲明為受保護的或者是私人的。
class 的存取權限
把關鍵字放在class之前,可以聲明該class的存取權限,需要注意的是
1、每個檔案中只能有一個public類用來表現單一的介面,檔案內可以存在為了支援public類而存在的friendly類;
2、public類的名稱必須和所在檔案的檔案名稱相同,包括大小寫也要一致;
3、當檔案內不包含任何public類的時候,你可以使用任意名稱做為檔案名稱;
4、class的存取控制符不能是private或者是protected的,只能是friendly和public的,如果你希望別人無法產生對象,你只要把建構函式聲明為private的就可以了
習題解答
1、撰寫一個程式,在其中產生ArrayList對象,但是不能明確匯入 java.util.*;
public class test
{
public static void main(String args[])
{
java.util.ArrayList al = new java.util.ArrayList();
}
}
6、撰寫一個具有public 、private、protected、friendly的資料成員和函數,並且產生一個對象進行觀察,當你取用類中成員的時候,有什麼編譯訊息?
package test;
public class test
{
public int a;
private int b;
protected int c;
int d;
public void methodA(){}
private void methodB(){}
protected void methodC(){}
void methodD(){}
public static void main(String args[])
{
test T = new test();
T.a=1;
T.b=1; //在不同/同一個包中cannot access the private members
T.c=1; //在不同的包中cannot access the protected members
T.d=1; //在不同的包中cannot access the friendly members
T.methodA();
T.methodB(); //在不同/同一個包中cannot access the private members
T.methodC(); //在不同的包中cannot access the protected members
T.methodD(); //在不同的包中cannot access the friendly members
}
}
7、撰寫一個class,讓他其中的成員具有protected,在同一個檔案內撰寫第二個class,並且在這裡操作第一個class中的protected資料
class protectedDemo
{
protected int i;
}
public class test
{
public static void main(String args[])
{
protectedDemo pd = new protectedDemo();
pd.i=10;
System.out.println(pd.i);
}
}
這個程式其實考察的是我們的"在同一個包中protected相當於包存取控制(friendly)"
12、Create the following file in the c05/local directory (presumably in your CLASSPATH):
//: c05:local:PackagedClass.java
//=M @echo compile by hand to see results
package c05.local;
class PackagedClass {
public PackagedClass() {
System.out.println(
"Creating a packaged class");
}
} ///:~
Then create the following file in a directory other than c05:
//: c05:foreign:Foreign.java
//=M @echo compile by hand to see results
package c05.foreign;
import c05.local.*;
public class Foreign {
public static void main (String[] args) {
PackagedClass pc = new PackagedClass();
}
} ///:~
Explain why the compiler generates an error. Would making the Foreign class part of the c05.local package change anything?
因為PackagedClass並非public的,而是friendly的,是包存取控制,只能在該包內的成員才能使用,如果把他放到和Foreign一樣的目錄,那麼他們等於說是在同一個包中,當然可以順利訪問。
這一章主要就是將了一下存取控制符,基本上不是很難,下一章我們講解重複運用class