學習Kotlin之泛型實化

2022-10-08 22:03:22 字數 2628 閱讀 3939

j**a中是沒有泛型實化這個概念的,不過為了深刻理解泛型實化,還需要了解一下j**a的泛型擦除機制。

在jdk 1.5之前,j**a是沒有泛型功能的,那個時候諸如list之類的資料結構可以儲存任意型別的資料,取出資料時也要手動向下轉型,不僅麻煩,還很危險。於是在jdk 1.5中,j**a引入了泛型功能。

實際上,j**a的泛型功能是通過型別擦除機制實現的。就是說泛型對於型別的約束只在編譯時期存在,執行的時候仍然會按照jdk 1.5之前的機制來執行,jvm是識別不出來我們在**中指定的泛型型別的。比如:我們建立了乙個list集合,在編譯時期只能向集合中新增字串型別的元素,但是在執行時期jvm並不能知道它本來只打算包含哪些型別的元素,只能識別出來它是個list。

所有基於jvm的語言,它們的泛型功能都是通過型別擦除機制來實現的,其中也包括了kotlin。這種機制使得我們不可能使用a is t或者t::class.j**a這樣的語法,因為t的實際型別在執行的時候已經被擦除了。

然而不同的是,kotlin提供了內聯函式的概念,內聯函式中的**會在編譯的時候自動被替換到呼叫它的地方,這樣的話就不存在泛型型別擦除的問題了。因為**在編譯之後會直接使用實際的型別替代內聯函式中的泛型宣告,其工作原理圖如下:

bar()是乙個帶有泛型型別的內聯函式,foo()函式呼叫了bar()函式,在**編譯之後,bar()函式中的**將可以獲得泛型的實際型別。

這說明,kotlin中是可以將內聯函式中的泛型進行實化的。

那麼具體怎麼寫呢?

首先,該函式必須是內聯函式。其次,在宣告泛型的地方加上reified關鍵字來表示該泛型要進行實化。

inline fun getgenerictype()
上述的泛型t就是乙個被實化的泛型。

那麼借助泛型實化,可以實現什麼樣的效果呢?

這裡我們準備實現乙個獲取泛型實際型別的功能:

inline fun getgenerictype() = t::class.j**a
雖然只有一行**,但是卻實現了乙個j**a中不可能實現的功能:getgenerictype()函式直接返回了當前指定泛型的實際型別。

t.class這樣的語法在j**a中是不合法的,但是在kotlin中,借助泛型實化功能就可以使用t::class.j**a這樣的語法。

現在我們對getgenerictype()函式進行測試:

fun main()
這裡給getgenerictype()函式指定了兩種不同的泛型,由於getgenerictype()函式會將指定泛型的具體型別返回,因此這裡直接將返回結果列印。

泛型實化功能允許我們在泛型函式中獲得泛型的實際型別,這就使得類似於a is t、t::class.j**a這樣的語法成為了可能。而靈活運用這一特性將可以實現一些不可思議的語法結構。

比如使用intent的時候:

val intent = intent(context,secondactivity::class

.j**a)

context.startactivity(intent)

會有secondactivity::class.j**a這樣的語法結構,而kotlin的泛型實化功能能讓我們有用更好的選擇。

新建乙個reified.kt檔案,編寫如下**:

inline fun startactivity(context: context)
這裡定義了乙個startactivity()函式,該函式接收乙個context引數,並同時使用inline和reified關鍵字讓泛型t成為了乙個被實化的泛型。接下來就是神奇的地方了,intent接收的第二個引數本來應該是乙個具體activity的class型別,但由於現在t已經是乙個被實化的泛型了,因此這裡我們可以直接傳入t::class.j**a。最後呼叫context的startactivity()方法來完成activity的啟動。

現在想要啟動secondactivity,只需要這樣寫;

startactivity(context)
kotlin能夠識別出指定泛型的實際型別,並啟動相應的activity。

**精簡了許多,這就是泛型實化帶來的功能。

不過現在的startactivity()函式還是有問題的,因為在啟用activity的時候可能會使用intent附帶一些引數。這裡需要借助高階函式來解決,新增乙個新的startactivity()函式過載,如下所示:

inline fun startactivity(context: context, block: intent.() ->unit)
這裡新增了乙個函式型別引數,並且它的函式型別是定義在intent類中的。

建立了intent例項後,呼叫該函式型別引數,並把intent例項傳入,這樣呼叫startactivity()函式的時候就可以在lambda表示式中為intent傳遞引數了,如下所示:

startactivity(this

)

這樣我們就做到了簡化啟動activity的用法了。

Kotlin筆記之泛型(一)

泛型類和函式 型別引數約束 泛型允許定義帶型別形參的型別,當這種型別的例項被建立出來的時候,型別形參被替換成稱為型別實參的具體型別 例項 原始碼listof函式宣告 funlistof vararg elements t list val list listof hello world 編譯器推導 ...

泛型之泛型類

public class a 構造引數型別上使用泛型 public a t t 方法返回值上使用泛型 public t gett 方法的引數上使用泛型 這是泛型類的方法,而不是泛型方法 public void sett t t 方法的返回值和引數型別上使用泛型 public t foo t t pu...

泛型之泛型類

public class a 構造引數型別上使用泛型 public a t t 方法返回值上使用泛型 public t gett 方法的引數上使用泛型 這是泛型類的方法,而不是泛型方法 public void sett t t 方法的返回值和引數型別上使用泛型 public t foo t t pu...