這個(gè)系列,結(jié)合IDEA的Inspection和我自己的理解編寫。
抽象問(wèn)題
1. 把實(shí)例造型(cast)成具體的類型
這個(gè)問(wèn)題的含義是,當(dāng)?shù)玫揭粋€(gè)實(shí)例時(shí),把它c(diǎn)ast到一個(gè)更加具體的類型使用。這個(gè)問(wèn)題存在于以下場(chǎng)景:
- 出于個(gè)人原因,比如只熟悉這個(gè)具體的類型、不動(dòng)腦筋的編碼。
這是新手常見(jiàn)的問(wèn)題。比如可能程序員只熟悉ArrayList,并不知道其上的更加抽象的接口;或者個(gè)人感覺(jué)ArrayList更加“好用”。這是不應(yīng)該出現(xiàn)的問(wèn)題,有經(jīng)驗(yàn)的程序員應(yīng)該指導(dǎo)初學(xué)者,避免犯錯(cuò)。
- 需要的方法不在更抽象的類型中,只在具體類型中才有定義。
這個(gè)問(wèn)題更多的表示了設(shè)計(jì)層面考慮的不充分。比如組織本身的代碼(非外來(lái)代碼),接口定義的類型不能滿足接口實(shí)現(xiàn)者的具體需求;返回值的類型過(guò)于泛化;本地變量(Local variable)定義的類型過(guò)于泛化等等。這些問(wèn)題一般意味著在設(shè)計(jì)上考慮不周,導(dǎo)致了對(duì)象交互過(guò)程中的“對(duì)接不順利”,這是設(shè)計(jì)上的不一致,需要對(duì)設(shè)計(jì)進(jìn)行仔細(xì)評(píng)估。以下是幾個(gè)這樣的例子:
public Collection aMethod(Collection c) {
List list = (List)c;
Object o = list.get(0); // Collection中沒(méi)有g(shù)et方法。導(dǎo)致實(shí)現(xiàn)者必須cast。
...
}
public void test() {
// 返回值必須cast才能使用更加具體的方法。
List alist = (List)aMethod(Arrays.asList(new String[]{"1", "2"}));
Object obj = alist.get(0);
...
}
public someMethod() {
MyInterface mi = new MyImplementation();
...
// 大部分時(shí)間調(diào)用MyInterface中的方法,但忽然發(fā)現(xiàn)有某個(gè)地方需要調(diào)用特定的非接口實(shí)現(xiàn):
int count = ((MyImplementation)mi).specialMethod();
...
}
最后這個(gè)例子,可能是方法的實(shí)現(xiàn)本身的問(wèn)題,比如完全可以直接使用MyImplementation來(lái)定義變量mi;也可能是抽象問(wèn)題,即沒(méi)有把本來(lái)具有普遍性的方法放到接口中,而是放到了具體實(shí)現(xiàn)中。
上面談到的設(shè)計(jì)問(wèn)題,是指的組織內(nèi)部的設(shè)計(jì)。在很多時(shí)候,需要使用外部的接口和實(shí)現(xiàn),這些接口因?yàn)榭紤]了更加廣泛的使用環(huán)境而采用了更加泛化的接口。這就需要順應(yīng)已經(jīng)存在的設(shè)計(jì)來(lái)實(shí)現(xiàn),不得不使用cast。但同時(shí)也要注意,在不得不cast的時(shí)候,一定要安全的使用cast,比如安全檢查或者安全的類型轉(zhuǎn)換,下面是示例:
public boolean equals(Object o) {
if (o == null) return false;
if (o instanceof MyClass) { // 安全檢查!
MyClass mc = (MyClass)o;
// 調(diào)用MyClass中的特定方法。
...
}
public method() {
Collection c = aMethodReturnsCollection();
List list = new ArrayList(c); //安全的類型轉(zhuǎn)換,把Collection轉(zhuǎn)換成List。
...
}
Coding, issue, abstract, cast