Kodien原理詳解

一個(gè)依賴(lài)注入框架,無(wú)非就是注入與獲取實(shí)例。那么kodein是怎么注入的?

注入

val kodein = Kodein {
    bind<Die>() with singleton { Die(instance()) } 

    bind<Random>() with singleton { Random(instance) } 
    constant(tag "max") with 5 
}

可以看到首先要初始化Kodien環(huán)境台猴,

KodeinImpl

internal open class KodeinImpl internal constructor(private val _container: KodeinContainerImpl) : Kodein {

    @Suppress("unused")
    private constructor(builder: KodeinMainBuilderImpl, runCallbacks: Boolean) : this(KodeinContainerImpl(builder.containerBuilder, builder.externalSources, builder.fullDescriptionOnError, runCallbacks))

    constructor(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit) : this(newBuilder(allowSilentOverride, init), true)

    companion object {
        private fun newBuilder(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit) = KodeinMainBuilderImpl(allowSilentOverride).apply(init)

        fun withDelayedCallbacks(allowSilentOverride: Boolean = false, init: Kodein.MainBuilder.() -> Unit): Pair<Kodein, () -> Unit> {
            val kodein = KodeinImpl(newBuilder(allowSilentOverride, init), false)
            return kodein to { kodein._container.initCallbacks?.invoke() ; Unit }
        }
    }

    final override val container: KodeinContainer by lazy {
        if (_container.initCallbacks != null)
            throw IllegalStateException("Kodein has not been initialized")
        _container
    }

}

這里會(huì)內(nèi)部構(gòu)建好一個(gè)Kodien.Builder,調(diào)用初始化函數(shù)后,傳入一個(gè)container

這里KodienBuilder通過(guò)調(diào)用bind返回一個(gè)binder,供上層去綁定一個(gè)實(shí)例

Binders

所以我們看到builder其實(shí)提供了一個(gè)bind方法,對(duì)外暴露接口獲取binder卿吐。

inner class TypeBinder<T : Any> internal constructor(val type: TypeToken<out T>, val tag: Any?, val overrides: Boolean?) : Kodein.Builder.TypeBinder<T> {
    internal val containerBuilder get() = this@KodeinBuilderImpl.containerBuilder

    override infix fun <C, A> with(binding: KodeinBinding<in C, in A, out T>) = containerBuilder.bind(Kodein.Key(binding.contextType, binding.argType, type, tag), binding, moduleName, overrides)
}

inner class DirectBinder internal constructor(private val _tag: Any?, private val _overrides: Boolean?) : Kodein.Builder.DirectBinder {
    override infix fun <C, A, T: Any> from(binding: KodeinBinding<in C, in A, out T>) {
        if (binding.createdType == UnitToken) {
            throw IllegalArgumentException("Using `bind() from` with a *Unit* ${binding.factoryName()} is most likely an error. If you are sure you want to bind the Unit type, please use `bind<Unit>() with ${binding.factoryName()}`.")
        }
        containerBuilder.bind(Kodein.Key(binding.contextType, binding.argType, binding.createdType, _tag), binding, moduleName, _overrides)
    }
}

inner class ConstantBinder internal constructor(private val _tag: Any, private val _overrides: Boolean?) : Kodein.Builder.ConstantBinder {
    @Suppress("FunctionName")
    override fun <T: Any> With(valueType: TypeToken<out T>, value: T) = Bind(tag = _tag, overrides = _overrides) from InstanceBinding(valueType, value)
}

然后我們來(lái)看看binder可以綁定哪些binding

Bindings

/**
 * @param C The type of the context used by the retriever.
 * @param A The type of argument used to create or retrieve an instance.
 * @param T The type of instance this factory creates or retrieves.
*/
interface Binding<C, A, T: Any> {

    fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T
}

Binding是什么旁舰,就是根據(jù)key返回一個(gè)構(gòu)造器,這個(gè)構(gòu)造器接受一個(gè)參數(shù)返回一個(gè)實(shí)例嗡官。

Factory

class Factory<C, A, T: Any>(override val contextType: TypeToken<in C>, override val argType: TypeToken<in A>, override val createdType: TypeToken<out T>, private val creator: BindingKodein<C>.(A) -> T) : KodeinBinding<C, A, T> {

    override fun factoryName() = "factory"

    override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T = { arg -> this.creator(kodein, arg) }
}

Multiton

class Multiton<C, A, T: Any>(override val scope: Scope<C>, override val contextType: TypeToken<in C>, override val argType: TypeToken<in A>, override val createdType: TypeToken<out T>, refMaker: RefMaker? = null, val sync: Boolean = true, private val creator: SimpleBindingKodein<C>.(A) -> T) : KodeinBinding<C, A, T> {
    private val _refMaker = refMaker ?: SingletonReference

    private val _scopeId = Any()


    override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T {
        val registry = scope.getRegistry(kodein.context)
        return { arg ->
            @Suppress("UNCHECKED_CAST")
            registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T
        }
    }

    override val copier = KodeinBinding.Copier { Multiton(scope, contextType, argType, createdType, _refMaker, sync, creator) }
}

首先通過(guò)scope.getRegistry(kodein.context)拿到registry,啥意思箭窜,拿到一個(gè)存儲(chǔ)實(shí)例的registry,這里可以和生命周期(context)綁定。

registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T

對(duì)于scopeKey(是data class)衍腥,可以看到如果arg一樣是不會(huì)create的磺樱,如果不存在的話,通過(guò)creator()函數(shù)創(chuàng)建一個(gè)

Provider

class Provider<C, T: Any>(override val contextType: TypeToken<in C>, override val createdType: TypeToken<out T>, val creator: NoArgBindingKodein<C>.() -> T) : NoArgKodeinBinding<C, T> {
    override fun factoryName() = "provider"

    override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, Unit, T>): (Unit) -> T = { NoArgBindingKodeinWrap(kodein).creator() }
}

Singleton

class Singleton<C, T: Any>(override val scope: Scope<C>, override val contextType: TypeToken<in C>, override val createdType: TypeToken<out T>, refMaker: RefMaker? = null, val sync: Boolean = true, val creator: NoArgSimpleBindingKodein<C>.() -> T) : NoArgKodeinBinding<C, T> {
    @Suppress("UNCHECKED_CAST")
    private val _refMaker = refMaker ?: SingletonReference
    private val _scopeKey = ScopeKey(Any(), Unit)

    /**
     * @see [KodeinBinding.getFactory]
     */
    override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, Unit, T>): (Unit) -> T {
        val registry = scope.getRegistry(kodein.context)
        return {
            @Suppress("UNCHECKED_CAST")
            registry.getOrCreate(_scopeKey, sync) { _refMaker.make { NoArgBindingKodeinWrap(BindingContextedKodein(kodein, kodein.context)).creator() } } as T
        }
    }

    override val copier = KodeinBinding.Copier { Singleton(scope, contextType, createdType, _refMaker, sync, creator) }
}

InstanceBinding

class InstanceBinding<T: Any>(override val createdType: TypeToken<out T>, val instance: T) : NoArgKodeinBinding<Any?, T> {
    override fun factoryName() = "instance"
    override val contextType = AnyToken

    /**
     * @see [KodeinBinding.getFactory]
     */
    override fun getFactory(kodein: BindingKodein<Any?>, key: Kodein.Key<Any?, Unit, T>): (Unit) -> T = { this.instance }


}

就返回一個(gè)已經(jīng)初始化好的instance

Eager

class EagerSingleton<T: Any>(builder: KodeinContainer.Builder, override val createdType: TypeToken<out T>, val creator: NoArgSimpleBindingKodein<Any?>.() -> T) : NoArgKodeinBinding<Any?, T> {

    override val contextType = AnyToken

    @Volatile private var _instance: T? = null
    private val _lock = Any()

    private fun getFactory(kodein: BindingKodein<Any?>): (Unit) -> T {
        return { _ ->
            synchronizedIfNull(
                    lock = _lock,
                    predicate = this@EagerSingleton::_instance,
                    ifNotNull = { it },
                    ifNull = {
                        NoArgBindingKodeinWrap(kodein).creator().also { _instance = it }
                    }
            )
        }
    }


    init {
        val key = Kodein.Key(AnyToken, UnitToken, createdType, null)
        builder.onReady { getFactory(BindingKodeinImpl(this, key, null, 0)).invoke(Unit) }
    }

    override val copier = KodeinBinding.Copier { builder -> EagerSingleton(builder, createdType, creator) }
}

builder.onReady,當(dāng)kodein容器??準(zhǔn)備好時(shí)就通過(guò)getFactory初始化實(shí)例

這里我們暫時(shí)知道bindings就是返回一個(gè)函數(shù)婆咸,這個(gè)函數(shù)傳入?yún)?shù)能返回我們需要的實(shí)例T竹捉。

那么binderbinding是怎么結(jié)合起來(lái)的,就通過(guò)一個(gè)初始化好的KodeinContainerBuilder去對(duì)bindings進(jìn)行配置尚骄。

KodeinContainerBuilderImpl

配置bindings

internal class KodeinContainerBuilderImpl(
        allowOverride: Boolean,
        silentOverride: Boolean,
        internal val bindingsMap: MutableMap<Kodein.Key<*, *, *>, MutableList<KodeinDefining<*, *, *>>>,
        internal val callbacks: MutableList<DKodein.() -> Unit>,
        internal val translators: MutableList<ContextTranslator<*, *>>
)

配置能否override,持有bindingMap,

Bind

當(dāng)開(kāi)始綁定時(shí),會(huì)將綁定關(guān)系放入bindingMap

val bindings = bindingsMap.getOrPut(key) { newLinkedList() }
bindings.add(0, KodeinDefining(binding, fromModule))

Extend

配置可以從已有的kodeinContainer中繼承

  override fun extend(container: KodeinContainer, allowOverride: Boolean, copy: Set<Kodein.Key<*, *, *>>) {
        checkMatch(allowOverride)

        container.tree.bindings.forEach { (key, bindings) ->
            if (!allowOverride)
                checkOverrides(key, null)

            val newBindings = if (key in copy) {
                newLinkedList<KodeinDefining<*, *, *>>().also {
                    bindings.mapTo(it) { KodeinDefining(it.binding.copier?.copy(this@KodeinContainerBuilderImpl) ?: it.binding, it.fromModule) }
                }
            }
            else {
                newLinkedList<KodeinDefining<*, *, *>>(bindings)
            }

            bindingsMap[key] = newBindings
        }

        translators += container.tree.registeredTranslators
    }

獲取實(shí)例

前面bb了這么多块差,那怎么獲取實(shí)例呢?

private val viewModel: AlbumListViewModel by instance()

fun <T : Any> KodeinAware.Instance(type: TypeToken<out T>, tag: Any? = null): KodeinProperty<T> =
        KodeinProperty(kodeinTrigger, kodeinContext) { ctx, _ -> kodein.container.provider(Kodein.Key(ctx.anyType, UnitToken, type, tag), ctx.value).invoke() }

這里返回一個(gè)lazy屬性倔丈,

KodeinProperty

kodein使用lazy能力憨闰。

通過(guò)定義 provideDelegate 操作符,可以擴(kuò)展創(chuàng)建屬性實(shí)現(xiàn)所委托對(duì)象的邏輯:
解釋

interface LazyDelegate<out V> {
    /** @suppress */
    operator fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<V>
}


class KodeinProperty<out V>(internal val trigger: KodeinTrigger?, val originalContext: KodeinContext<*>, private val get: (KodeinContext<*>, String) -> V) : LazyDelegate<V> {

    override fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<V> = lazy {
        @Suppress("UNCHECKED_CAST")
        val context = if (receiver != null && originalContext === AnyKodeinContext) KodeinContext(TTOf(receiver) as TypeToken<in Any>, receiver) else originalContext
        get(context, prop.name) } .also { trigger?.properties?.add(it)
    }

}

class KodeinPropertyMap<in I, out O>(private val base: KodeinProperty<I>, private val map: (I) -> O) : LazyDelegate<O> {

    override fun provideDelegate(receiver: Any?, prop: KProperty<Any?>): Lazy<O> = lazy { map(base.provideDelegate(receiver, prop).value) }.also { base.trigger?.properties?.add(it) }

}

翻譯一下:
假設(shè)一個(gè)var prop: Type by KodeinProperty() =>

class C {
    // calling "provideDelegate" to create the additional "delegate" property
    private val prop$delegate = KodeinProperty().provideDelegate(this, this::prop)
    val prop: Type
        get() = prop$delegate.getValue(this, this::prop)
}

這里返回了lazy,即當(dāng)這個(gè)屬性被用到時(shí)需五,會(huì)調(diào)用get方法

那我們?cè)賮?lái)看看這段代碼:

fun <A, T : Any> KodeinAware.Factory(argType: TypeToken<in A>, type: TypeToken<out T>, tag: Any? = null): KodeinProperty<(A) -> T> =
        KodeinProperty(kodeinTrigger, kodeinContext) { ctx, _ -> kodein.container.factory(Kodein.Key(ctx.anyType, argType, type, tag), ctx.value) }

看源碼可以看到Factory&Instance的不同鹉动,前者lazy返回一個(gè)N階函數(shù),后者lazy直接返回一個(gè)實(shí)例宏邮。

所以很簡(jiǎn)單泽示,就是通過(guò)kodein.container.factory去獲取。

KodeinContainerImpl

獲取factory,什么是工廠蜜氨,就是別人傳入一個(gè)A(arg)返回自己需要的實(shí)例械筛。

tree.find(key)

首先在樹(shù)中根據(jù)鍵值尋找,kodein在綁定關(guān)系的時(shí)候初始化了一個(gè)containerimpl, 初始化了一顆樹(shù)记劝,

tree.find(key, 0).let {
    if (it.size == 1) {
        val (_, definition, translator) = it[0]
        node?.check(key, 0)
        val kContext = translator?.toKContext(context) ?: KodeinContext(key.contextType, context) as KodeinContext<Any>
        key as Kodein.Key<Any, A, T>
        val bindingKodein = bindingKodein(key, kContext, definition.tree, overrideLevel)
        return definition.binding.getFactory(bindingKodein, key)
    }
}

如果找到一個(gè)(有且一個(gè))变姨,拿到definition,即binding的定義族扰。檢查是否有循環(huán)依賴(lài)

bindingKodein
val bindingKodein = bindingKodein(key, kContext, definition.tree, overrideLevel)
return definition.binding.getFactory(bindingKodein, key)

這里會(huì)創(chuàng)建一個(gè)bindingKodein的東西厌丑,在bindingsgetFactory,為什么要傳入這么一個(gè)東西呢渔呵?

NoArgBindingKodeinWrap(BindingContextedKodein(kodein, kodein.context)).creator()

我們知道在實(shí)例化一個(gè)類(lèi)時(shí)怒竿,這個(gè)類(lèi)可能還會(huì)依賴(lài)其他類(lèi),綁定可能如下:

bind<AlbumDetailViewModel>() with scoped<Fragment>(AndroidLifecycleScope).singleton {
    KotlinViewModelProvider.of(context) { AlbumDetailViewModel(instance(), instance()) }
}

在里面還需要instance()實(shí)例化扩氢,那為什么不能直接用kodein的環(huán)境呢耕驰,因?yàn)榘垂倬W(wǎng)說(shuō)法,還可以進(jìn)行override:

val testModule = Kodein.Module(name = "test") {
    bind<Logger>(overrides = true) with singleton { FileLoggerWrapper("path/to/file", overriddenInstance()) } 
}

所以其實(shí)bindingKodein也是kodein環(huán)境:

internal open class BindingKodeinImpl<out C, out A, out T: Any> internal constructor(
        override val dkodein: DKodein,
        private val _key: Kodein.Key<C, A, T>,
        override val context: C,
        private val _overrideLevel: Int
) : DKodein by dkodein, BindingKodein<C> {
    override fun overriddenFactory(): (Any?) -> Any = container.factory(_key, context, _overrideLevel + 1) as (Any?) -> Any
    override fun overriddenFactoryOrNull(): ((Any?) -> Any)? = container.factoryOrNull(_key, context, _overrideLevel + 1) as ((Any?) -> Any)?
}

它包括什么录豺,它包括DKodien, Dkodien又是一個(gè)新的概念朦肘,

If you don’t want to use delegated properties, Kodein has you covered. Most of the features available to Kodein are available to DKodein (D is for Direct). DKodein allows you to directly get a new instance or dependency

它就比kodein少了delegate屬性饭弓,因此也沒(méi)有receiver & lazy的概念。

override fun overriddenFactory(): (Any?) -> Any = container.factory(_key, context, _overrideLevel + 1) as (Any?) -> Any

正常綁定時(shí)使用的是container.factory(0),這里會(huì)使用+1表明使用override

循環(huán)依賴(lài) node.check

val kodein = Kodein {
    bind<Die>() with singleton { Die(instance()) } 

    bind<Random>() with singleton { Random(instance) } 
    constant(tag "max") with 5 
}
org.kodein.di.Kodein$DependencyLoopException: Dependency recursion:
     bind<View>()
    ╔╩>bind<Presenter>()
    ║  ╚>bind<View>()
    ╚════╝

回顧一下媒抠,
弟断,當(dāng)我們調(diào)用by instance時(shí)會(huì)發(fā)生什么,會(huì)返回一個(gè)函數(shù)趴生,函數(shù)執(zhí)行時(shí)會(huì)調(diào)用
kodein.container.provider(Kodein.Key(ctx.anyType, UnitToken, type, tag), ctx.value).invoke(),即調(diào)用creator,即Die(instance()),這里調(diào)用instance()時(shí),背后調(diào)用DKodeinBaseImpl.container.provider.invoke(),那這里的container是誰(shuí)呢阀趴,先看DKodeinBaseImpl是誰(shuí),就是調(diào)用by instancecontainer,所以這里container都是同一個(gè),很正常能看出循環(huán)依賴(lài)苍匆。

我們看刘急,在找factory時(shí)

private tailrec fun recursiveCheck(node: Node, searchedKey: Kodein.Key<*, *, *>, searchedOverrideLevel: Int): Boolean {
    return if (node.key == searchedKey && node.overrideLevel == searchedOverrideLevel)
        false
    else if (node.parent == null)
        true
    else
        recursiveCheck(node.parent, searchedKey, searchedOverrideLevel)
}

開(kāi)始NodeDie, 然后NodeRandom,然后 searchKeydie, 因此在遞歸上去時(shí)node -> parent又是die,導(dǎo)致循環(huán)依賴(lài)浸踩。

KodeinTreeImpl

一個(gè)緩存:

private val _cache: MutableMap<Kodein.Key<*, *, *>, Triple<Kodein.Key<*, *, *>, List<KodeinDefinition<*, *, *>>, ContextTranslator<*, *>?>>
private typealias BoundTypeTree = MutableMap<TypeChecker, ContextTypeTree>

private typealias ContextTypeTree = MutableMap<TypeChecker.Down, ArgumentTypeTree>

private typealias ArgumentTypeTree = MutableMap<TypeChecker.Down, TagTree>

private typealias TagTree = MutableMap<Any?, Kodein.Key<*, *, *>>

其中因?yàn)?code>kodien可以override,所以會(huì)有definition lists:

val kodein = Kodein {
    bind<API>() with singleton { APIImpl() }
    /* ... */
    bind<API>(overrides = true) with singleton { OtherAPIImpl() }
}

尋找過(guò)程

  • _cache[key]先從key中尋找
  • _cache[anyContextKey]尋找anyContextKey 當(dāng)然translator.contextType = key.contextType

Inject or Retrieve

inject

class Controller(private val ds: DataSource) {
    /*...*/
}
val controller by kodein.newInstance { Controller(instance()) }

這里會(huì)走到Controller(instance()), 在instance里會(huì)自己去取實(shí)例叔汁。

retrive

class Controller(override val kodein: Kodein): KodeinAware {
    private val ds: DataSource by instance()
}

這兩種方式,一種是自己就是一個(gè)kodein = KodeinAware 內(nèi)部會(huì)去取實(shí)例检碗,另一種是自己由外部注入攻柠。

SubTypes

val kodein = Kodein {
    bind<Controller>().subtypes() with { type ->
        when (type.jvmType) { 
            is MySpecialController::class.java -> singleton { MySpecialController() }
            else -> provider { myControllerSystem.getController(type.jvmType) }
        }
    }
}

看到這里問(wèn)題,我綁定的是T后裸,這個(gè)T的子類(lèi)也會(huì)找到:

data class Down(override val type: TypeToken<*>) : TypeChecker() {
    val isAny = (type == AnyToken)
    override fun check(other: TypeToken<*>) = isAny || type.isAssignableFrom(other)
}

Contexted & Scoped

kodien中瑰钮,所有binder with binding都會(huì)帶一個(gè)scope&context:對(duì)于默認(rèn)的是AnyToken&NoScope

override val contextType = AnyToken

override val scope: Scope<Any?> get() = NoScope() // Recreating a new NoScope every-time *on purpose*!

那么,假設(shè)我們想要綁到一個(gè)具體的context&scope時(shí)微驶,可以按如下這么寫(xiě):

val kodein = Kodein {
    bind<Writer>() with contexted<Request>.provider { context.response.writer } 
}
val kodein = Kodein {
    bind<Session>() with scoped(requestScope).singleton { context.openSession() } 
}

val session: Session by kodein.on(context = request).instance()

Scopes are derived from the context variable.

這里context<Request> & scoped(requestScope)會(huì)返回一個(gè)新的builder,綁定新的context&scope, 當(dāng)使用kodein.on時(shí)會(huì)創(chuàng)建一個(gè)新的kodein,kodeinContext是傳入的request,我們?cè)賮?lái)重看一下getFactory:

override fun getFactory(kodein: BindingKodein<C>, key: Kodein.Key<C, A, T>): (A) -> T {
    val registry = scope.getRegistry(kodein.context)
    return { arg ->
        @Suppress("UNCHECKED_CAST")
        registry.getOrCreate(ScopeKey(_scopeId, arg), sync) { _refMaker.make { BindingContextedKodein(kodein, kodein.context).creator(arg) } } as T
    }
}

我們舉個(gè)scope的例子:

open class AndroidLifecycleScope private constructor(private val newRegistry: () -> ScopeRegistry) : Scope<LifecycleOwner> {

    companion object multiItem: AndroidLifecycleScope(::StandardScopeRegistry)

    object singleItem: AndroidLifecycleScope(::SingleItemScopeRegistry)

    private val map = HashMap<LifecycleOwner, ScopeRegistry>()

    override fun getRegistry(context: LifecycleOwner): ScopeRegistry {
        return synchronizedIfNull(
                lock = map,
                predicate = { map[context] },
                ifNotNull = { it },
                ifNull = {
                    val registry = newRegistry()
                    map[context] = registry
                    context.lifecycle.addObserver(object : LifecycleObserver {
                        @OnLifecycleEvent(Lifecycle.Event.ON_DESTROY)
                        fun onDestroy() {
                            context.lifecycle.removeObserver(this)
                            registry.clear()
                            map.remove(context)
                        }
                    })
                    registry
                }
        )
    }
}

TypedReference

p05ut8ksb6.png

講的挺好

  • TypeVariable(類(lèi)型變量):比如List<T>中的T等
  • WildcardType( 泛型表達(dá)式類(lèi)型):例如List< ? extends Number>這種
  • ParameterizedType(參數(shù)化類(lèi)型):就是我們平常所用到的泛型List浪谴、Map(注意和TypeVariable的區(qū)別)
  • GenericArrayType(數(shù)組類(lèi)型):并不是我們工作中所使用的數(shù)組String[] 、byte[](這種都屬于Class)因苹,而是帶有泛型的數(shù)組苟耻,即T[] 泛型數(shù)組
private fun Type._checkIsReified(disp: Any) {
    when (val jvmType = javaType) {
        is Class<*> -> {}
        is ParameterizedType -> for (arg in jvmType.actualTypeArguments) arg._checkIsReified(disp)
        is GenericArrayType -> jvmType.genericComponentType._checkIsReified(disp)
        is WildcardType -> {
            for (arg in jvmType.lowerBounds)
                arg._checkIsReified(disp)
            for (arg in jvmType.upperBounds)
                arg._checkIsReified(disp)
        }
        is TypeVariable<*> -> throw IllegalArgumentException("$disp uses a type variable named ${jvmType.name}, therefore, the bound value can never be retrieved.")
        else -> throw IllegalArgumentException("Unknown type ${jvmType.javaClass} $jvmType")
    }
}

反正就是一定要具體化泛型,不要有<T>這種

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末扶檐,一起剝皮案震驚了整個(gè)濱河市凶杖,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌款筑,老刑警劉巖智蝠,帶你破解...
    沈念sama閱讀 216,544評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異奈梳,居然都是意外死亡杈湾,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)攘须,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)漆撞,“玉大人,你說(shuō)我怎么就攤上這事「〔担” “怎么了悍汛?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,764評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)至会。 經(jīng)常有香客問(wèn)我员凝,道長(zhǎng),這世上最難降的妖魔是什么奋献? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,193評(píng)論 1 292
  • 正文 為了忘掉前任健霹,我火速辦了婚禮,結(jié)果婚禮上瓶蚂,老公的妹妹穿的比我還像新娘糖埋。我一直安慰自己,他們只是感情好窃这,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,216評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布瞳别。 她就那樣靜靜地躺著,像睡著了一般杭攻。 火紅的嫁衣襯著肌膚如雪祟敛。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,182評(píng)論 1 299
  • 那天兆解,我揣著相機(jī)與錄音馆铁,去河邊找鬼。 笑死锅睛,一個(gè)胖子當(dāng)著我的面吹牛埠巨,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播现拒,決...
    沈念sama閱讀 40,063評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼辣垒,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了印蔬?” 一聲冷哼從身側(cè)響起勋桶,我...
    開(kāi)封第一講書(shū)人閱讀 38,917評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎侥猬,沒(méi)想到半個(gè)月后例驹,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,329評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡陵究,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,543評(píng)論 2 332
  • 正文 我和宋清朗相戀三年眠饮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片铜邮。...
    茶點(diǎn)故事閱讀 39,722評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出松蒜,到底是詐尸還是另有隱情扔茅,我是刑警寧澤,帶...
    沈念sama閱讀 35,425評(píng)論 5 343
  • 正文 年R本政府宣布秸苗,位于F島的核電站召娜,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏惊楼。R本人自食惡果不足惜玖瘸,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,019評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望檀咙。 院中可真熱鬧雅倒,春花似錦、人聲如沸弧可。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,671評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)棕诵。三九已至裁良,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間校套,已是汗流浹背价脾。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,825評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留笛匙,地道東北人彼棍。 一個(gè)月前我還...
    沈念sama閱讀 47,729評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像膳算,于是被迫代替她去往敵國(guó)和親座硕。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,614評(píng)論 2 353