聊聊Kotlin中的元编程
背景
首先還是來說下為什么出現(xiàn)元編程?
一個(gè)技術(shù)的出現(xiàn)肯定是不滿足現(xiàn)狀,那么元編程的出現(xiàn)是為了解決什么問題呢?舉一個(gè)栗子,比如我們需要獲取某個(gè)類的屬性進(jìn)行賦值取值或者獲取函數(shù)信息進(jìn)行調(diào)用時(shí),我們當(dāng)然可以編寫代碼以讓外界訪問這些數(shù)據(jù),但是這樣做容易出錯(cuò)而且特別麻煩,這個(gè)時(shí)候我們可以想到利用反射也可以達(dá)到同樣的效果。對(duì)吧,獲取類變量,函數(shù)信息這看起來就是反射可以做到的事情,所以其實(shí)反射也屬于元編程范疇。
什么是元數(shù)據(jù)
顧名思義,元數(shù)據(jù)和元注解一個(gè)道理,元注解是標(biāo)記注解的注解,元數(shù)據(jù)自然就是描述數(shù)據(jù)的數(shù)據(jù),這個(gè)聽起來有點(diǎn)繞口,來解釋一些這兩個(gè)“數(shù)據(jù)”到底分別指代什么?
描述“數(shù)據(jù)”的“數(shù)據(jù)”
我們知道我們的需求也就是程序是通過各種數(shù)據(jù)構(gòu)建起來的,這些數(shù)據(jù)就是指類,函數(shù),變量…等是對(duì)現(xiàn)實(shí)世界和需求的描述,這就是第一個(gè)數(shù)據(jù)的意思
通過類,變量,函數(shù)這些數(shù)據(jù)去描述需求程序
那么第二個(gè)數(shù)據(jù)也就知道了,是用來描述類,函數(shù),變量的數(shù)據(jù),這就是第二個(gè)數(shù)據(jù)的意思,也就是元數(shù)據(jù)。
通過元數(shù)據(jù)描述類,變量,函數(shù)信息
什么是元編程
直接說定義:操作元數(shù)據(jù)的編程就是指元編程。
比如我們通過反射獲取類,屬性,方法的一些信息,進(jìn)而操作他們這也叫元編程。所以上面說到反射也算元編程的范疇。
但是這么說又太片面了,反射是通過程序獲取數(shù)據(jù),而元編程還包括通過數(shù)據(jù)獲取程序。即“程序即是數(shù)據(jù),數(shù)據(jù)即是程序”。
可以這么說元編程是更高階的抽象,高階函數(shù)用函數(shù)作為輸入輸出。而元編程用程序作為輸入輸出。
程序即是數(shù)據(jù)
這個(gè)很好理解,通過指定的程序來獲取構(gòu)成這個(gè)程序的信息,比如一個(gè)Book類,我們可以動(dòng)態(tài)的獲取這個(gè)類中的屬性和行為,其實(shí)就是反射。
介紹
來看下Java中的反射信息結(jié)構(gòu)
可以看到有參數(shù),類,包這些信息,AccessibleObject信息代表的是可調(diào)用的元素。
比如Field指字段(僅僅代表字段),Excutable代表可執(zhí)行其中包括構(gòu)造函數(shù)和普通方法。
再來看下Kotlin中的反射結(jié)構(gòu):
Kclass代表類信息,Kparameter代表參數(shù)信息,而KCallable和Accessible一樣代表的都是可調(diào)用的元素。
其分為兩類,KFunction和KProperty,不同點(diǎn)是:
- KProperty中包含普通屬性和可變屬性KMutableProperty,且Kotlin中的屬性包含Setter和Getter方法。。而java中的Field只代表這個(gè)字段,setget是在另外一個(gè)Method結(jié)構(gòu)中
- KFunction統(tǒng)一了構(gòu)造函數(shù),包含Kproperty的Setter和Getter。而java中的Method還分為構(gòu)造函數(shù)和普通函數(shù),且是單獨(dú)的setget方法不是Field自帶的
- Java中反射需要設(shè)置可訪問性,而Kotlin中的屬性自帶setget方法通過get可直接獲取。也就是KProprity.call(對(duì)象實(shí)例)即可獲取屬性。
- Kotlin中獲取信息比Java更明確直觀。
Kotlin的增強(qiáng)
和java中的反射一樣使用,不同的是Kotlin中由于多了很多特性所以其元數(shù)據(jù)類型也比java中多,比如:
metaclass描述類的類型kclass。
通過類名::class得到kclass
KClass中相比Java中的Class新增:
KCallable由于包含著KFunction和KProperty,所以先來看下KCallable中有哪些屬性:
KCallable可通過KClass的members成員獲取,其返回值是Collection<KCallable<*>>
通過上面的信息已經(jīng)可以獲取到了類,屬性和方法的信息,那么我們?cè)撊绾潍@取參數(shù)信息呢?
參數(shù)信息又分為這三種:方法的參數(shù)信息,方法的返回值信息,泛型的參數(shù)信息(也就是參數(shù)類型)。
可通過KCallable.parameters獲取方法的參數(shù)信息,返回值是List< KParameter >。
KParameter新增屬性:、
可看到通過Kparameter的type屬性獲取到參數(shù)的類型,那么返回值的類型和泛型類型該如何獲取呢?
上面講解KCallable的時(shí)候就已經(jīng)有這兩個(gè)屬性了:
- 返回值類型:只有方法才有返回值,所以是通過KCallable的returntype屬性可以獲取到
- 參數(shù)類型:泛型一種是泛型方法還有一種是泛型類。泛型方法一樣通過KCallable的typeParameters獲取,在KClass中通過startProjectedType屬性獲取。返回值是List< KTypeParameter >不存在返回一個(gè)空的集合。
數(shù)據(jù)即是程序
這句話該怎么理解。我們倒推一下,通過一些信息來動(dòng)態(tài)創(chuàng)建程序。
比如使用字節(jié)碼工具ASM,javassist等動(dòng)態(tài)生成類,還有使用KAPT注解處理器通過注解來手動(dòng)輸出程序到一個(gè)文件中。可以看到和Kotlin好像沒有多大關(guān)系,所以Kotlin目前還沒法做到動(dòng)態(tài)創(chuàng)建程序。
注解處理器
Kotlin中的注解處理器和Java中的一樣,注解參數(shù)為常量,作用范圍為:
- 基本類型
- 字符串
- Class對(duì)象
- 注解
- 類型數(shù)組,XXXArray
定義方式:比Java中更明顯:用annotation修飾類即可。
使用方式:
1.添加注解處理器信息。這需要在classpath里包含META-INFO/services/javax.annotation.processing.Processor文件,并將注解處理器包名和類名寫入該文件。
2.使用kapt插件。如果是gradle工程可以通過apply plugin:'kotlin-kapt’添加注解處理器支持。
kapt也支持生成Kotlin代碼。
缺點(diǎn)
雖然annotation processor允許開發(fā)人員訪問程序AST(抽象語法樹可查看之前文章JVM編譯只是),但沒有提供行之有效的代碼生成方案,目前僅有的代碼生成方案也僅僅是將代碼以字符串的形式寫入新文件,而無法做到直接將生成的AST作為程序。這也說明了Java和Kotlin目前不具備同像性。
元編程的使用范圍
1.外部程序:kotlin的語法糖suger,最終會(huì)變成java文件。所以編譯器承擔(dān)了 解語法糖 的角色,編譯器作為外部程序去操作這些語法糖(本質(zhì)也是元數(shù)據(jù))也叫作元編程
2.獲取運(yùn)行時(shí)數(shù)據(jù)(反射)
3.動(dòng)態(tài)執(zhí)行代碼(目前無法做到)
元編程需要一定的學(xué)習(xí)成本,需要了解class結(jié)構(gòu)和kclass等相關(guān)程序構(gòu)成的數(shù)據(jù)。
總結(jié)
以上是生活随笔為你收集整理的聊聊Kotlin中的元编程的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 谈谈mysql的悲观和乐观锁 - 周伯通
- 下一篇: 数单词