java基礎(chǔ)之泛型簡(jiǎn)單講解通俗易懂 List集合和數(shù)組區(qū)別?
List集合和數(shù)組區(qū)別?不同的是,:數(shù)組的大小是固定的,而鏈表的大小是可以改變的;Array可以存儲(chǔ)基本類型數(shù)據(jù)和引用類型數(shù)據(jù)(基本類型/引用類型),list只能存儲(chǔ)引用類型變量;數(shù)組只能存儲(chǔ)相同類型
List集合和數(shù)組區(qū)別?
不同的是,:數(shù)組的大小是固定的,而鏈表的大小是可以改變的;Array可以存儲(chǔ)基本類型數(shù)據(jù)和引用類型數(shù)據(jù)(基本類型/引用類型),list只能存儲(chǔ)引用類型變量;數(shù)組只能存儲(chǔ)相同類型的數(shù)據(jù),而list不要求;數(shù)組按下標(biāo)排序,而列表按數(shù)據(jù)的放置順序排序。
Java泛型問題,為什么不能使用,基本數(shù)據(jù)類型,求詳細(xì)一點(diǎn)兒?
通用形式要求可以包含對(duì)象類型,而基本類型在java中不屬于對(duì)象。
Java為什么不能實(shí)現(xiàn)真正泛型?
一句話回答:Java守信用!
Java在發(fā)布之初就把二進(jìn)制兼容的承諾寫進(jìn)了《Java虛擬機(jī)規(guī)范》,最終為了兼容Java1.5之前的版本選擇了這個(gè)方案
雖然兼容方案不僅僅是擦除,但這一承諾確實(shí)是它沒有采用C#這樣的真正泛型方案的最重要原因。
java怎么獲取一個(gè)泛型方法的真實(shí)泛型類型?
在我看來(lái),如果通過一個(gè)方法獲取一個(gè)泛型方法的真正泛型類型是可行的,就不應(yīng)該實(shí)現(xiàn)。
首先,Java中的泛型也叫參數(shù)化類型。我沒記錯(cuò)的話,泛型應(yīng)該是jdk5推出的一個(gè)特性。泛型的目的是使數(shù)據(jù)類型能夠作為參數(shù)傳入,這樣變量的數(shù)據(jù)類型就可以動(dòng)態(tài)地改變。
那么什么是泛型方法呢?也就是說(shuō),泛型類型是在方法上聲明的,只有在調(diào)用方法時(shí)才會(huì)傳入真正的類型。如果在方法內(nèi)部獲取,直接調(diào)用泛型對(duì)象的getClass方法即可。但是如果你想通過一個(gè)方法得到一個(gè)泛型方法的真實(shí)類型,我不知道。;我認(rèn)為這不可能實(shí)現(xiàn)。因?yàn)樵诓徽{(diào)用方法的時(shí)候,真正的數(shù)據(jù)類型還沒有進(jìn)入,所以無(wú)法得到泛型對(duì)應(yīng)的真正類型。
所以讓我來(lái)談?wù)勅绾卧诜盒头椒ㄖ蝎@得真正的泛型類型。
像往常一樣,讓 讓我們寫一個(gè)代碼并解釋一下。通用方法的示例如下:
c語(yǔ)言可以泛型編程嗎?如何實(shí)現(xiàn)?
泛型編程是一種非常常見的編程方法。主要目的是實(shí)現(xiàn)靜態(tài)綁定,使函數(shù)可以接受不同類型的參數(shù),并在編譯時(shí)確定正確的類型。
許多語(yǔ)言都支持泛型編程。例如,在C中,可以使用函數(shù)模板和類模板來(lái)實(shí)現(xiàn)泛型編程。在單一繼承的語(yǔ)言中,如Java、Objective-C或C#,也可以使用similar和NSObject類型進(jìn)行編程。在具有類型推理功能的編程語(yǔ)言(如Swift)中,可以直接使用泛型編程。
但C語(yǔ)言是高級(jí)語(yǔ)言編程的基礎(chǔ)語(yǔ)言,如何用C語(yǔ)言實(shí)現(xiàn)泛型編程確實(shí)是個(gè)問題。首先,C語(yǔ)言不支持函數(shù)重載和模板類型,實(shí)現(xiàn)起來(lái)真的很難。
0x01通用指針(void*)導(dǎo)言
Void *是C語(yǔ)言中的一種類型。眾所周知,在大多數(shù)編程語(yǔ)言中,void類型表示所謂的空類型,比如一個(gè)函數(shù)返回一個(gè)空類型void,這是非常常見的用法。
注意:void的返回值并不意味著沒有返回值,而是意味著返回一個(gè)空類型,這也是為什么你仍然可以在這些函數(shù)中使用return語(yǔ)句的原因。只有某些語(yǔ)言中的構(gòu)造函數(shù)和析構(gòu)函數(shù)沒有返回值。在這些函數(shù)中,不允許使用return語(yǔ)句。它們是顯著不同的。Objective-C是一種獨(dú)特的語(yǔ)言,它的類初始化方法是一種普通的方法,返回值是instancetype(當(dāng)前類的指針類型)。
Void *可能有點(diǎn)不為人知。void *可以表示C語(yǔ)言中任何類型的指針。說(shuō)到底,對(duì)于一個(gè)存儲(chǔ)單元的地址來(lái)說(shuō),它存儲(chǔ)的所謂數(shù)據(jù)類型只是每次取的字節(jié)數(shù)不一樣,這些存儲(chǔ)單元的地址本身并沒有什么不同。下面會(huì)更好的體現(xiàn)這句話的意思。
void *的大小永遠(yuǎn)是一個(gè)字,就像普通的指針一樣。具體大小因機(jī)器字長(zhǎng)而異,例如32位機(jī)器為4字節(jié),64位機(jī)器為8字節(jié)。
我還沒有 t在16位8086機(jī)上驗(yàn)證了指針的大小,因?yàn)?086的地址是20位。有興趣的可以回去試試。
個(gè)人認(rèn)為指針大小還是16位,因?yàn)?0位是物理地址,物理地址是從段地址和偏移地址計(jì)算出來(lái)的。匯編后,C語(yǔ)言中的指針可能只是變成了相對(duì)于段地址的偏移地址。畢竟對(duì)于8086來(lái)說(shuō),數(shù)據(jù)永遠(yuǎn)在DS段,而代碼永遠(yuǎn)在CS段。(斜體表示未經(jīng)核實(shí)的陳述)
在C語(yǔ)言中,其他常用類型的指針可以自動(dòng)轉(zhuǎn)換為void * type,而void * type只能強(qiáng)制轉(zhuǎn)換為其他常用類型的指針,否則會(huì)出現(xiàn)警告或錯(cuò)誤。
關(guān)于所謂的void *指向數(shù)組有一個(gè)特別大的坑,這里直接用代碼解釋。
void Swap(void *array,int x,int y,int mallocsize) {
void *temp malloc(mallocsize)
memcpy(temp,數(shù)組mallocsize*x,mallocsize)
memcpy(數(shù)組mallocsize*x,數(shù)組mallocsize*y,mallocsize)
memcpy(數(shù)組mallocsize*y,temp,mallocsize)
免費(fèi)(臨時(shí))
}
這是一次經(jīng)典的交流。函數(shù),借助臨時(shí)變量temp,不過這個(gè)函數(shù)是通用的,后面會(huì)介紹memcpy的用法。需要注意的是,如果array指向一個(gè)數(shù)組,你可以 t直接用amparray[x]或者array x來(lái)獲取指向x元素的地址,因?yàn)関oid *類型的默認(rèn)指針偏移量是1,和char *一樣,對(duì)于大多數(shù)類型都會(huì)造成錯(cuò)誤。因此,在使用泛型類型時(shí),我們必須知道它的原始長(zhǎng)度。我們需要一個(gè)名為mallocsize的int類型參數(shù)來(lái)告訴我們這個(gè)值,并在計(jì)算指針偏移量時(shí)乘以它。這相當(dāng)于C編程中的模板類型定義或者Java中的泛型參數(shù)。
同時(shí)要注意void *類型的指針,它可以 不要在任何時(shí)候被取消參考(或者老師過去叫什么 "獲取內(nèi)容 "在課堂上?),原因很明顯:void類型的變量是不合法的。因此,如果要解引用,必須先將其轉(zhuǎn)換成普通指針。當(dāng)在數(shù)組中使用時(shí),還應(yīng)該注意解引用操作符優(yōu)先于加法操作符,所以應(yīng)該加上括號(hào),如下所示:
int a *(數(shù)組mallocsize * x)
這段代碼完美體現(xiàn)了C語(yǔ)言編程的丑陋。
0x02 sizeof運(yùn)算符簡(jiǎn)介
Sizeof運(yùn)算符相信學(xué)過C語(yǔ)言的朋友都很熟悉,但知道sizeof是運(yùn)算符的人不多,返回的類型是size_t類型。sizeof運(yùn)算符返回類型占用的空間量。這里唯一的要點(diǎn)是,如果你找到一個(gè)指針類型或數(shù)組名的大小(事實(shí)上,數(shù)組名是一個(gè)指針常量),返回的結(jié)果總是一個(gè)單詞(見上文)。求一個(gè)結(jié)構(gòu)類型的sizeof不是簡(jiǎn)單的結(jié)構(gòu)中各種類型的sizeof之和,而是涉及到內(nèi)存對(duì)齊的問題。我不 這里不想介紹了。詳情請(qǐng)?jiān)L問:如何理解struct的內(nèi)存對(duì)齊?-智虎。
0x03 memcpy功能簡(jiǎn)介
Memcpy是一個(gè)經(jīng)常和void *一起使用的函數(shù),它的函數(shù)原型是:
void * memcpy(void *,const void *,size_t)
頭文件屬于string.h,可以看到,這個(gè)函數(shù)本身是以void * type作為參數(shù)和返回值的,其實(shí)很好理解。這是一個(gè)賦值和復(fù)制記憶的過程。將第二個(gè)參數(shù)指向的內(nèi)存復(fù)制到第一個(gè)參數(shù),復(fù)制的字節(jié)數(shù)由第三個(gè)參數(shù)指定。當(dāng)然,第三個(gè)參數(shù)通常是通過sizeof運(yùn)算符獲得的,所以我贏了 這里就不舉例了。我還沒有 我沒有研究過返回值,也沒有研究過。;我沒用過。如果有知道的朋友可以評(píng)論一下。
0x04泛型編程在C語(yǔ)言中的實(shí)現(xiàn)
話雖如此,我們還沒有 t還沒有提到泛型編程。但是,如上所述,一般的思路是使用void * type作為泛型指針,然后使用類似于mallocsize的參數(shù)來(lái)指定占用的內(nèi)存大小。占用的內(nèi)存大小是通過sizeof運(yùn)算符獲得的。如果需要賦值,可以使用memcpy函數(shù)來(lái)完成。下面是一個(gè)直接的例子,這是一個(gè)通用的快速排序來(lái)說(shuō)明這些問題:
#ifndef Compare_h
#定義比較_h
#包含ltstdio.hgt
#包含JCB.h
int IsGreater(void *x,void *y)
int IsGreaterOrEqual(void *x,void *y)
int IsSmaller(void *x,void *y)
int IsSmallerOrEqual(void *x,void *y)
#endif /* Compare_h */
//
// Compare.c
//作業(yè)調(diào)度程序
//
//魯創(chuàng)作于2017/11/16。
//版權(quán)?2017魯饒威。保留所有權(quán)利。
//
#包含比較. h
int IsGreater(void *x,void *y) {
return *(int *)x gt *(int *)y
}
int IsGreaterOrEqual(void *x,void *y) {
return *(int *)x gt *(int *)y
}
int IsSmaller(void *x,void *y) {
return *(int *)x lt *(int *)y
}
int IsSmallerOrEqual(void *x,void *y) {
return *(int *)x lt *(int *)y
}
//
// QuickSort.h
//作業(yè)調(diào)度程序
//
//魯創(chuàng)作于2017/11/16。
//版權(quán)?2017魯饒威。保留所有權(quán)利。
//
#ifndef快速排序_h
#定義快速排序_h
#包含ltstdio。高度
#包含ltstdlib.hgt
#包含ltstring.hgt
#包含比較. h
void QuickSort(void *array,int left,int right,int mallocsize)
#endif /* QuickSort_h */
//
// QuickSort.c
//作業(yè)調(diào)度程序
//
//魯創(chuàng)作于2017/11/16。
//版權(quán)?2017魯饒威。保留所有權(quán)利。
//
#包含快速排序. h
void Swap(void *array,int x,int y,int mallocsize) {
void *temp malloc(mallocsize)
memcpy(temp,數(shù)組mallocsize*x,mallocsize)
memcpy(數(shù)組mallocsize*x,數(shù)組mallocsize*y,mallocsize)
memcpy(數(shù)組mallocsize*y,temp,mallocsize)
免費(fèi)(臨時(shí))
}
int QuickSortSelectCenter(int l,int r) {
返回(左側(cè))/2
}
int quick sort partition(void * array,int l,int r,int mallocsize) {
int left l
int右r
void *temp malloc(mallocsize)
memcpy(temp,數(shù)組mallocsize*right,mallocsize)
while(左左右){
while(IsSmallerOrEqual(array mallocsize * left,temp) ampamp left lt right) {
左邊的
}
if(左lt右){
memcpy(數(shù)組mallocsize*right,數(shù)組mallocsize*left,mallocsize)
正確
}
while ( IsGreaterOrEqual(array mallocsize*right,temp) ampamp left lt right) {
正確
}
if(左lt右){
memcpy(數(shù)組mallocsize*left,數(shù)組mallocsize*right,mallocsize)
左邊的
}
}
memcpy(數(shù)組mallocsize*left,temp,mallocsize)
向左返回
}
void QuickSort(void *array,int left,int right,int mallocsize) {
if (leftgtright) {
返回
}
中間中心快速排序選擇中心(左,右)
交換(數(shù)組、中心、右側(cè)、mallocsize)
center QuickSortPartition(數(shù)組,左,右,mallocsize)
快速排序(數(shù)組,左,中心-1,mallocsize)
快速排序(數(shù)組,中心1,右側(cè),mallocsize)
}
這里有個(gè)懸念,明明可以直接比較,何必用很多函數(shù)來(lái)完成,也就是關(guān)于Compare.h使用的問題,答案會(huì)在下面揭曉。
0x05泛型的協(xié)議問題
剛才那個(gè)問題涉及到一個(gè)通用的協(xié)議問題,我借用了Objective-C的一個(gè)概念在這里詳細(xì)闡述。就像那個(gè)問題一樣,既然我的快速排序是泛型的,那我怎么保證傳入的實(shí)際泛型參數(shù)一定是可比較的呢?比如很明顯int,float,double是可以比較的,我們也理解char使用ASCII編碼方案的比較,字符串類型甚至可以比較。但是如何比較其他語(yǔ)言中的對(duì)象呢?這是一個(gè)問題。在C中,我們可以重載運(yùn)算符,所以我們?nèi)匀豢梢允褂帽容^運(yùn)算符,并使用運(yùn)算符來(lái)重載函數(shù)。但是Java和Objective-C呢?而如果傳入的泛型參數(shù)沒有實(shí)現(xiàn)對(duì)應(yīng)的運(yùn)算符重載函數(shù)呢?這時(shí),有必要引入一個(gè)協(xié)議的概念。簡(jiǎn)單地說(shuō),如果一個(gè)類型想要成為一個(gè)排序泛型函數(shù)的泛型參數(shù),你必須實(shí)現(xiàn)一個(gè)可比較的關(guān)聯(lián)。討論一下。這個(gè)協(xié)議在Swift語(yǔ)言中叫做Comparable,這樣在編譯的時(shí)候,編譯器就會(huì)知道這個(gè)泛型參數(shù)是可以比較的,從而完成我們的操作,否則就會(huì)出錯(cuò)。這是泛型中的協(xié)議問題。
0x06摘要
C語(yǔ)言的泛型編程以void *為泛型類型,本質(zhì)上是一個(gè)泛型指針。
C語(yǔ)言中的泛型編程需要知道泛型類型變量的內(nèi)存大小,這可以通過sizeof獲得并傳遞給泛型函數(shù)。
在C語(yǔ)言的泛型編程中,要注意數(shù)組的偏移量。void *的默認(rèn)偏移量是1,對(duì)于大多數(shù)類型來(lái)說(shuō)是錯(cuò)誤的,需要自己編程轉(zhuǎn)換。
Memcpy函數(shù)用于在C語(yǔ)言的泛型編程中復(fù)制和賦值泛型變量。
在C語(yǔ)言的泛型編程中,我們也需要注意協(xié)議問題,但是在C中,我們只能自己編寫函數(shù)來(lái)定義,可以使用其他語(yǔ)言現(xiàn)成的接口或協(xié)議。