三個關(guān)鍵詞訪問修飾符:private(私有的=類級別的)、未指定(包級私有的)、protected(受保護的=繼承級別的+包級別的訪問)、pulbic(共有的)
懷遠網(wǎng)站建設(shè)公司成都創(chuàng)新互聯(lián),懷遠網(wǎng)站設(shè)計制作,有大型網(wǎng)站制作公司豐富經(jīng)驗。已為懷遠上千提供企業(yè)網(wǎng)站建設(shè)服務(wù)。企業(yè)網(wǎng)站搭建\成都外貿(mào)網(wǎng)站建設(shè)要多少錢,請找那個售后服務(wù)好的懷遠做網(wǎng)站的公司定做!備注:其中未指定,使用的是默認的訪問級別,包內(nèi)部的任何類都可以訪問這個成員。如果類或者接口是包級私有的,就應(yīng)該做成包級私有的。包級私有的是這個包實現(xiàn)的一部分,而不是這個報API的一部分,包級私有的可以更改實現(xiàn)、修改或去除,不必擔(dān)心傷害到客戶,如果是共有的,你就要永遠支持它,并且保持兼容性。
經(jīng)驗表明,盡可能地使每一個類或成員都不被外界訪問。即,在保證軟件功能正確的前提下,使用最低的訪問級別。
公有類不應(yīng)該包含公有域,除了后面的共有靜態(tài)final域的特殊情形——通過公有域的靜態(tài)final域來暴露類的常量。按照慣例,這樣的域的名字由大寫字母構(gòu)成,單詞之間用下劃線隔開(見三十八)。很重要的一點是,這個域要么包含原語類型的值,要么包含指向非可變對象的引用(見十三)。
注意:非零長度的數(shù)組總是可變的,所以具有共有靜態(tài)final數(shù)據(jù)域幾乎總是錯誤的。如果一個類包含這樣的一個域,客戶能夠修改數(shù)組中的內(nèi)容。這是安全漏洞的一個常見根源:
//潛在的安全漏洞public static final Type[] VALUES={……};
共有數(shù)組應(yīng)該被替換成私有數(shù)組,以及一個共有的非可變列表:
private static final Type[] PRIVATE_VALUES={……};
public static final List VALUES=
Collection.unmodifiableList(Arrays.asList(PRIVATE_VALUES))
非可變性類是一個簡單的類,它的實例不能被修改。每個實例中包含的所有信息都必須在該實例被創(chuàng)建的時候就提供出來,并且在對象的整個生命周期保持不變。Java平臺庫包含許多非可變類,其中String、原語類型的包裝類、BigInteger和BigDecimal。
非可變類要遵循的五條規(guī)則:
如:public static final Complext ZERO=new Complex(0,0);
這種方法可以進一步擴展,一個非可變對象可以提供一些靜態(tài)工廠,它們吧頻繁用到的實例緩存起來,當(dāng)請求一個預(yù)先存在的實例的時候,可以不再創(chuàng)建新的實例。BigInteger和Boolean都有這樣的靜態(tài)工廠。使用這樣的靜態(tài)工廠可以使得客戶之間可以共享已有的實例,而不是創(chuàng)建新的實例,從而降低內(nèi)存占用和垃圾回收的代價。
注:StringBuffer是String類的可變配套類,在特定的環(huán)境下,相對BigInteger而言,BigSet是String類的可變配套類。StringBuffer是可變對象,可以對字符串進行改寫,主要是insert和append兩個方法,用于多線程。而StringBuilder是JDK1.5之后才加入的,和StringBuffer沒有本質(zhì)區(qū)別,但是在單線程的情況下使用,速度更快。
下面是延遲初始化技術(shù)的習(xí)慣用法:
//不可變對象的緩存,延遲初始化函數(shù)private volatile Foo cacheFooVal=UNLIKE_FOO_VALUE
public Foo foo(){
Foo result=cachedFooVal;
if(result==UNLIKE_FOO_VALUE)
result=cachedFooVal=fooVal();
return result;
}
//fool值的私有幫助函數(shù)private Fool fooVal(){}
與方法不同的是,繼承打破了封裝性。能用組合完成的就用組合,組合優(yōu)先于繼承。
用組合的方式可以避免有不合適的繼承所帶來的問題。使用組合不在擴展一個已有的類,而是在新類中增加一個私有域,它引用了這個類的一個實例。新類中的每個實例方法都可以調(diào)用被包含已有實例中對應(yīng)的方法,并返回它的結(jié)果。這被稱為轉(zhuǎn)發(fā)(forwarding),新類中的方法被稱為轉(zhuǎn)發(fā)方法(forwarding method)。這樣的類將會非常穩(wěn)固,它不依賴已有類的實現(xiàn)細節(jié)。即使已有的類增加了新的方法,也不會影響新的類。
// 使用組合取代繼承的包裝類public class InstrumentedSet implements Set {
private final Set s;
private int addCount = 0;
public InstrumentedSet(Set s) {
this.s = s;
}
public boolean add(Object o) {
addCount++;
return s.add(o);
}
public boolean addAll(Collection c) {
addCount+= c.size();
return s.addAll(c);
}
public int getAddCount() {
return addCount;
}
// 轉(zhuǎn)發(fā)方法 public void clear() { s.clear(); }
public boolean contains(Object o) { return s.contains(o); }
public boolean isEmpty() { return s.isEmpty(); }
public int size() { return s.size(); }
public Iterator iterator() { return s.iterator(); }
public boolean remove(Object o) { return s.remove(o); }
public boolean containsAll(Collection c)
{return s.containsAll(c); }
public boolean removeAll(Collection c)
{return s.removeAll(c); }
public boolean retainAll(Collection c)
{return s.retainAll(c); }
public Object[] toArray() { return s.toArray(); }
public Object[] toArray(Object[] a) { return s.toArray(a); }
public boolean equals(Object o) { return s.equals(o); }
public int hashCode() { return s.hashCode(); }
public String toString() { return s.toString(); }
}
這里的包裝類可以用來包裝任何一個Set實現(xiàn),并且可以與任何以前已有的構(gòu)造函數(shù)一起工作。如
Set s1=new InstrumentedSet(new TreeSet(list));
Set s2=new InstrumentedSet(new HashSet(capacity, loadFactor));
因為一個Instrument實例都把另一個 Set實例包裝了起來,所以我們稱其為包裝類。這也正是裝飾模式,因為Instrument對一個集合進行了修飾,為它增加了計數(shù)器的特性。有時候,修改和轉(zhuǎn)發(fā)這兩項技術(shù)的結(jié)合被錯誤的引用為“委托(delegation)”,從技術(shù)角度講,這不是委托,除非包裝類把自己傳遞給一個被包裝的對象。
對于專門為繼承而設(shè)計的類而言,需要滿足:
注:如果違反了第三條規(guī)則,很有可能會導(dǎo)致程序失敗。超類的構(gòu)造函數(shù)在子類的構(gòu)造函數(shù)之前運行,所以子類中改寫版本的方法將會在子類的構(gòu)造函數(shù)運行之前先被調(diào)用。如果改寫版本的方法依賴于子類構(gòu)造函數(shù)所執(zhí)行的初始化工作,那么該方法就不會如期執(zhí)行。
public class Super {
// 違反了規(guī)則 -構(gòu)造函數(shù)調(diào)用了重寫的方法 public Super() {
m();
}
public void m() {
}
}
下面的子類改寫了方法m,Super唯一的構(gòu)造函數(shù)就錯誤的調(diào)用了這個方法m:
final class Sub extends Super {
private final Date date; // 空的終結(jié)字段,由構(gòu)造函數(shù)設(shè)置
Sub() {
date= new Date();
}
// 重寫了 Super.m, 被Super的構(gòu)造函數(shù)調(diào)用 public void m() {
System.out.println(date);
}
public static void main(String[] args) {
Sub s= new Sub();
s.m();
}
本來期望打印出兩個日期,但是第一次打印出Null,因為方法被構(gòu)造函數(shù)Super()調(diào)用的時候,造函數(shù)Sub還沒有機會初始化data域。
這個的執(zhí)行順序是父類的構(gòu)造函數(shù)->重寫的方法(回到子類)->子類的構(gòu)造函數(shù)。
接口和抽象類都是允許多個實現(xiàn)的類型。兩者的區(qū)別是抽象類允許包含某些方法的實現(xiàn),但是接口不允許。實現(xiàn)一個抽象類的類型,它必須成為抽象類的子類。因為Java只允許單繼承,所以抽象類作為類型定義收到了極大的限制。
下面是一個靜態(tài)工廠方法,它包含了一個靜態(tài)的工廠方法,它包含一個完整的、功能全面的List實現(xiàn):
//整形數(shù)組的List適配器static List intArrayAsList(final int[] a){
if(a==null)
throw new NullPointerException();
return new AbstractList(){
public Object get(int i){
return new Integer(a[i]);
}
public int size(){
return a.length;
}
public Object set(int i, Object o){
int oldVal=a[i];
a[i]=((Integer)o).intValue();
return new Integer(oldVal);
}
};
}
這個例子是一個適配器模式,它使得int數(shù)組可以被看做一個Integer實例列表。這個例子只提供了一個靜態(tài)工廠,并且這個類是一個可被訪問的匿名類,它被隱藏在靜態(tài)工廠的內(nèi)部。
下面是Map.Entry接口的骨架實現(xiàn)類:
public abstract class AbstractMapEntry implements Map.Entry {
// 基本的 public abstract Object getKey();
public abstract Object getValue();
// 要改變maps的實體必須要重寫的方法 public Object setValue(Object value) {
throw new UnsupportedOperationException();
}
// 實現(xiàn)Map.Entry.equals的通用約定 public boolean equals(Object o) {
if (o == this)
return true;
if (! (o instanceof Map.Entry))
return false;
Map.Entry arg= (Map.Entry)o;
return eq(getKey(), arg.getKey()) &&
eq(getValue(), arg.getValue());
}
private static boolean eq(Object o1, Object o2) {
return (o1 == null ? o2 == null : o1.equals(o2));
}
// 實現(xiàn)Map.Entry.hashCode的通用約定 public int hashCode() {
return
(getKey()== null ? 0 : getKey().hashCode()) ^
(getValue()== null ? 0 : getValue().hashCode());
}
}
當(dāng)一個類實現(xiàn)了一個接口的時候,這個接口被用做一個類型。通過這個類型可以引用這個類的實例。因此,一個類實現(xiàn)了某個接口,就表明客戶可以對這個類的實例實施某些動作。為了其他的目的而定義的接口是不合適的。
常量接口是對接口的不良使用,下面是常量接口的例子:
// 常量接口模式- 請勿使用!public interface PhysicalConstants {
// Avogadro's number (1/mol) static final double AVOGADROS_NUMBER = 6.02214199e23;
// Boltzmann constant (J/K) static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
// Mass of the electron (kg) static final double ELECTRON_MASS = 9.10938188e-31;
}
導(dǎo)出常量的幾種可行方案:
// 常量工具類public class PhysicalConstants {
private PhysicalConstants() { }// 防止實例化
public static final double AVOGADROS_NUMBER = 6.02214199e23;
public static final double BOLTZMANN_CONSTANT = 1.3806503e-23;
public static final double ELECTRON_MASS = 9.10938188e-31;
}
總之,接口是被用來定義類型的,它們不應(yīng)該被導(dǎo)出常量。
嵌套類(nested class)是指被定義在一個類的內(nèi)部的類。嵌套類存在的目的是為外圍的類提供服務(wù)。
嵌套類有四種:靜態(tài)成員類(static member class)、非靜態(tài)成員類(nostatic member class)、匿名類(anonymous class)和局部類(local class)。
除了第一種之外,其他三種都被成為內(nèi)部類(inner class)。靜態(tài)成員類是一種簡單的嵌套類,最好把它看做一個普通類,只是碰巧被聲明在類的內(nèi)部而已。
非靜態(tài)成員的另一個用法是定義一個Adapter,它允許外部類的一個實例被看做另一個不相關(guān)的實例。如,Map接口的實現(xiàn)往往使用非靜態(tài)成員類來實現(xiàn)它們的集合視圖(collection view),這些集合視圖是有Map的keySet、entrySet和Value方法返回的。類似地,諸如Set和List這樣的集合接口的實現(xiàn)往往也使用非靜態(tài)成員類來實現(xiàn)它們的迭代器。
//非靜態(tài)成員的典型用法public class MySet extends AbstractSet{
……//省去不相關(guān)的public Iterator iterator(){
return MyIterator();
}
priavateclass MyIterator implements Iterator{
……
}
}
如果你聲明的成員類不要求訪問外圍實例,那么請記住把static修飾符放到成員類的聲明中。
非靜態(tài)成員類需要訪問外圍實例,如果省略了static修飾符,則每個實例都將包含一個額外的指向外圍實例的引用,維護這份引用需要耗費時間和空間,但又沒有相應(yīng)的好處。
匿名類僅僅在使用的時候被聲明和實例化,行為與靜態(tài)成員類或非靜態(tài)成員類非常相似,取決于它所處的環(huán)境:如果匿名類出現(xiàn)在一個非靜態(tài)的環(huán)境中,則它有一個外圍實例。
匿名類通常出現(xiàn)在表達式的中間,可能20行或者更短,太長影響到程序的可讀性。
匿名類的一個通用方法是創(chuàng)建一個函數(shù)對象(function object),比如Comparator實例。例如,下面的方法調(diào)用對一組字符串按照其長度進行排序:
//匿名類的典型使用Arrays.sort(args, new Comparator(){
public int compare(Object o1, Object o2){
return ((String)o1).length()-((String)o2).length();
}
});
匿名類的另一個用法是創(chuàng)建一個過程對象(process object),比如Thread、Runable或者TimeTask實例。第三個常見用法是在一個靜態(tài)工廠方法的內(nèi)部(見十六intArrayAsList方法)。第四個常見的用法是在復(fù)雜的類型安全枚舉類型(它要求為每個實例提供單獨的子類)中,用于公有的靜態(tài)final域的初始化器中(見二十一Operation類)。如果Operation類是Calculator的一個靜態(tài)成員類,那么Operation類是雙重嵌套類。
// 公有靜態(tài)成員類的典型使用public class Calculator {
public static abstract class Operation {
private final String name;
Operation(String name) {this.name = name; }
public String toString() { return this.name; }
// 通過這一常量進行運算符表示 abstract double eval(double x, double y);
// 雙重嵌套匿名類 public static final Operation PLUS =new Operation("+") {
double eval(double x, double y) { return x + y; }
};
public static final Operation MINUS = new Operation("-") {
double eval(double x, double y) { return x - y; }
};
public static final Operation TIMES = new Operation("*") {
double eval(double x, double y) { return x * y; }
};
public static final Operation DIVIDE =new Operation("/") {
double eval(double x, double y) { return x / y; }
};
}
// 返回指定的計算結(jié)果 public double calculate(double x, Operation op, double y) {
return op.eval(x, y);
}
}
網(wǎng)頁標題:Java高效編程之三【類和接口】-創(chuàng)新互聯(lián)
分享地址:http://muchs.cn/article34/dsedpe.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、面包屑導(dǎo)航、手機網(wǎng)站建設(shè)、網(wǎng)站收錄、微信公眾號、網(wǎng)站導(dǎo)航
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)
猜你還喜歡下面的內(nèi)容