Kotlin 使用反射调用具有默认参数值的函数
考虑一个接口:Kotlin 使用反射调用具有默认参数值的函数,kotlin,kotlin-reflect,Kotlin,Kotlin Reflect,考虑一个接口: interface Foo { fun func(argWithDefault: String = "default") } 及其(最低限度)实施: class FooImpl() : Foo { override fun func(argWithDefault: String) { println(argWithDefault) } } 我也在尝试通过反射调用FooImpl上的func: val func = Foo::func va
interface Foo {
fun func(argWithDefault: String = "default")
}
及其(最低限度)实施:
class FooImpl() : Foo {
override fun func(argWithDefault: String) {
println(argWithDefault)
}
}
我也在尝试通过反射调用FooImpl
上的func
:
val func = Foo::func
val instance = FooImpl()
func.callBy(mapOf(func.instanceParameter!! to instance))
但我有以下例外:
kotlin.reflect.jvm.internal.KotlinReflectionInternalError:此可调用项不支持默认调用:public abstract fun func(argWithDefault:kotlin.String=…):com.example.Foo中定义的kotlin.Unit[DeserializedSimpleFunctionDescriptor@2d7275fc]
Foo::func.parameters[1]。等选项
返回true
,根据文档,等选项
返回
如果此参数是可选的,并且在通过KCallable.callBy进行调用时可以忽略,则为true,否则为false
所以我想这应该是可能的;dr:这似乎是一个已知的问题: 我以前做过一些分析: 如果我们看一下Kotlin在这里实际生成的内容,就会发现为什么不再有任何默认值。
Foo的字节码
:
public abstract interface Foo {
public abstract func(Ljava/lang/String;)V
LOCALVARIABLE this LFoo; L0 L1 0
LOCALVARIABLE argWithDefault Ljava/lang/String; L0 L1 1
public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
}
// ================Foo$DefaultImpls.class =================
public static synthetic func$default(LFoo;Ljava/lang/String;ILjava/lang/Object;)V
ALOAD 3
IFNULL L0
NEW java/lang/UnsupportedOperationException
DUP
LDC "Super calls with default arguments not supported in this target, function: func"
INVOKESPECIAL java/lang/UnsupportedOperationException.<init> (Ljava/lang/String;)V
ATHROW
L0
ILOAD 2
ICONST_1
IAND
IFEQ L1
L2
LINENUMBER 2 L2
LDC "default" // <--- here is our default value? but where are we? Foo$Defaults.func$default?
ASTORE 1
L1
ALOAD 0
ALOAD 1
INVOKEINTERFACE Foo.func (Ljava/lang/String;)V (itf)
RETURN
MAXSTACK = 3
MAXLOCALS = 4
public final static INNERCLASS Foo$DefaultImpls Foo DefaultImpls
// compiled from: Foo.kt
}
为了完整起见,我还创建了一个Caller.kt
,其中只包含以下代码:
fun main() = FooImpl().func()
最后是字节码,也是我们的DefaultImpls.func$default
-调用:
public final class CallerKt {
public final static main()V
L0
LINENUMBER 1 L0
NEW FooImpl
DUP
INVOKESPECIAL FooImpl.<init> ()V
ACONST_NULL
ICONST_1
ACONST_NULL
INVOKESTATIC Foo$DefaultImpls.func$default (LFoo;Ljava/lang/String;ILjava/lang/Object;)V // aha! here is our DefaultImpls.func$default!
RETURN
L1
MAXSTACK = 4
MAXLOCALS = 0
public final类CallerKt{
公共最终静态main()V
L0
1号线L0
新食品
重复
调用特殊的FooImpl
空的
ICONST_1
空的
INVOKESTATIC Foo$DefaultImpls.func$default(LFoo;Ljava/lang/String;ILjava/lang/Object;)V//aha!这是我们的DefaultImpls.func$default!
返回
L1
MAXSTACK=4
最大局部变量=0
因此,DefaultImpls
只是由编译器生成并在需要时使用,reflect
实用程序也可以(而且在我看来应该)反映这一事实……我添加了一个关于开放类的类似已知问题(它们也使用合成的…$default
-函数)如果这个问题不能完全解决你的担忧,你可能想开辟一个新的领域
只是稍微处理了一下链接问题……实际上,如果使用a::foo
而不是B::foo
(a
是开放类,B
扩展a
),那么那里的示例就可以工作了但是,由于A
基本上与您的Foo
-接口相似,因此该接口需要对此进行特殊处理
public final class CallerKt {
public final static main()V
L0
LINENUMBER 1 L0
NEW FooImpl
DUP
INVOKESPECIAL FooImpl.<init> ()V
ACONST_NULL
ICONST_1
ACONST_NULL
INVOKESTATIC Foo$DefaultImpls.func$default (LFoo;Ljava/lang/String;ILjava/lang/Object;)V // aha! here is our DefaultImpls.func$default!
RETURN
L1
MAXSTACK = 4
MAXLOCALS = 0