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