在數(shù)年的java編程經(jīng)驗(yàn)中,面向?qū)ο蠛头盒秃孟衩懿豢煞?都是為了實(shí)現(xiàn)多態(tài),那通過繼承實(shí)現(xiàn)和泛型各自的能力邊界在什么地方呢?
最近在嘗鮮c++,首先打算用c++來寫一套類框架集,首當(dāng)其沖被實(shí)現(xiàn)的是數(shù)組,內(nèi)存里一段連續(xù)的數(shù)據(jù)結(jié)構(gòu).當(dāng)時(shí)我就遇到一個(gè)問題,高級(jí)數(shù)組的類型是要用泛型T來實(shí)現(xiàn)還是用面向?qū)ο蟮腷ase model繼承來實(shí)現(xiàn):
//這樣的區(qū)別
ArrayList<T>
ArrayList<Object>
在這個(gè)數(shù)據(jù)實(shí)現(xiàn)的內(nèi)部,無論是T
還是Object
都是一個(gè)通用的符號(hào),用于API的封裝,期初我想讓數(shù)據(jù)的靈活度更好,并且元素更純凈,我選擇了'T'泛型這個(gè)方案,很順利的封裝好了數(shù)組,想著這樣既可以設(shè)置數(shù)組類型為基礎(chǔ)數(shù)據(jù)類型,也可以設(shè)置為對(duì)象,結(jié)果到了測(cè)試階段,發(fā)現(xiàn)一個(gè)問題,這個(gè)數(shù)組不能按照我的想法兼容對(duì)象和基礎(chǔ)數(shù)據(jù)類型,為啥呢?看一下下面這個(gè)API:
//獲取數(shù)組元素下標(biāo)
int indexOf(Object *node) {
Object *ptr = instance;
for (int i = 0; i < current_node_sum; ++i) {
//這里直接對(duì)比了指針的地址
if (node == ptr) {
return i;
}
ptr++;
}
return -1;
}
很普通的一個(gè)API,獲取數(shù)據(jù)元素下標(biāo),通過遞歸指針的方式遍歷了數(shù)組,然后比對(duì)遍歷的元素是不是形參上的元素,那么問題來了,怎么比? java中是equals
方法搞定的一切,c++呢? 對(duì)比指針地址,判斷元素在內(nèi)存中是否是同一個(gè)地址,來確定是否是同一個(gè)元素.好,那么問題又來了,看下面的代碼片段:
c++對(duì)比兩個(gè)不同種類的指針地址,直接編譯報(bào)錯(cuò),不符合c++規(guī)范,我們這里用泛型繞過了編譯器檢測(cè),這里如果數(shù)組是包裝類型,形參傳入的是基本類型,那怎么辦?就像下面這種情況:
ArrayList<Integer> list;
list.add(Integer(1));
//這里indexOf方法直接傳了一個(gè)1進(jìn)去
list.indexOf(1);
這樣的indexOf
方法因?yàn)楸容^了兩個(gè)不同類型的指針地址,直接報(bào)錯(cuò),沒招.
除非兩個(gè)條件滿足一個(gè):
1:不允許數(shù)組使用基本數(shù)據(jù)類型
2:數(shù)組元素?fù)碛?code>equals方法,杜絕對(duì)比不同類型指針的風(fēng)險(xiǎn)
然而無論是哪個(gè)條件都只有一個(gè)辦法能解決這個(gè)問題,沒錯(cuò),就是通過繼承base model的思路去實(shí)現(xiàn)高級(jí)數(shù)組.
這就是為什么java的類框架集里要有Object作為頂層超類,一方面出于雙親委托的加載模式的控制,另一方面就是和本文分析的原因一樣了,JDK隱藏指針的實(shí)現(xiàn),但是究竟怎么對(duì)比java中兩個(gè)對(duì)象呢?沒錯(cuò),就是通過比對(duì)兩個(gè)Object對(duì)象的指針地址,也就是Object 中this指針的地址:
仿造JDK我自己封裝了一個(gè)基類Object,實(shí)現(xiàn)了equals
方法,并將高級(jí)數(shù)組改造成元素繼承自O(shè)bject的實(shí)現(xiàn)方式
完美解決了這個(gè)問題.
Object.equals方法
bool Object::equals(Object &obj) {
return (this->self == obj.self);
}
改造后的ArrayList.indexOf方法
//獲取數(shù)組元素下標(biāo)
int indexOf(Object node) {
Object *ptr = instance;
for (int i = 0; i < current_node_sum; ++i) {
if (node.equals(*ptr)) {
return i;
}
ptr++;
}
return -1;
}