Kotlin中默认构造函数中的两个其他类型? [英] Two Additional types in default constructor in Kotlin?

查看:189
本文介绍了Kotlin中默认构造函数中的两个其他类型?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

由于我一直在使用 kotlin-reflect 调用默认值并声明了一个默认值,所以我看到了第二个不同的构造函数.

Since I've been using kotlin-reflect to invoke my default and declared one, I see second different constructor.

我认识到两个不同的字段 int arg3 kotlin.jvm.internal.DefaultConstructorMarker arg4 添加到了我的构造函数中.

I have realized that two different fields int arg3 and kotlin.jvm.internal.DefaultConstructorMarker arg4 added to my constructor.

data class Model(
    @SerializedName("xyz") val entity: String?,
    @SerializedName("abc") val id: Long? = null
)
val constructors = clazz.declaredConstructors // how I call the constructors

我的实际问题是为什么我要拥有这两个字段,其背后的逻辑是什么?

My actual question is why I have these 2 fields and what is the logic behind it ?

谢谢.

推荐答案

将这两个参数添加到Kotlin编译器为具有默认参数的所有函数和构造函数生成的特殊合成成员中.

These two parameters are added to special synthetic members generated by the Kotlin compiler for all functions and constructors with default parameters.

借助Java反射,您可以通过检查

With Java reflection, you can filter out these synthetic functions and constructors by checking isSynthetic() and finding the one that is not.

integer参数是位掩码.当从Kotlin调用此函数时,将生成位掩码并将其作为参数传递.这些位显示函数的哪些默认参数是传递的显式参数,哪些应使用默认值.

The integer parameter is a bit mask. When such a function is called from Kotlin, a bit mask is generated and passed as the argument. The bits show which of the default parameters of the function are passed explicit arguments and which should use the default value.

DefaultConstructorMarker参数用于确保合成构造函数(接受位掩码)与其他具有相同参数签名和最后一个Int签名的构造函数不发生冲突.传递给marker参数的参数不会被使用,它始终为null.

The DefaultConstructorMarker parameter is used to ensure there's no collision of the synthetic constructor (accepting the bit mask) with a different constructor which has a signature with those same arguments and an Int in the end. The argument passed to the marker parameter is not used in any way, and it is always null.

实际上,分别为每个函数或构造函数生成的两个方法或构造函数,至少具有一个默认参数:一个具有与声明的签名相同且没有其他参数的默认参数,另一个也接受位掩码和标记.

In fact, there are two methods or constructors generated for each function or constructor, respectively, that has at least one default parameter: one with the same signature as declared and no additional parameters, and the other also accepting a bit mask and the marker.

如果检查该函数的字节码,对于函数声明,您会发现大致如下:

If you inspect the bytecode of such a function, you will find roughly the following, for a function declaration:

fun foo(bar: String, baz: List<String> = emptyList(), qux: Set<String> = emptySet()) = 0

字节码中的实际方法是:

The real method in the bytecode is:

// access flags 0x19
// signature (Ljava/lang/String;Ljava/util/List<Ljava/lang/String;>;Ljava/util/Set<Ljava/lang/String;>;)I
// declaration: int foo(java.lang.String, java.util.List<java.lang.String>, java.util.Set<java.lang.String>)
public final static foo(
    Ljava/lang/String;
    Ljava/util/List;
    Ljava/util/Set;
)I
  // annotable parameter count: 3 (visible)
  // annotable parameter count: 3 (invisible)
  @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 0
  @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 1
  @Lorg/jetbrains/annotations/NotNull;() // invisible, parameter 2
L0
  ALOAD 0
  LDC "bar"
  INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
  ALOAD 1
  LDC "baz"
  INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
  ALOAD 2
  LDC "qux"
  INVOKESTATIC kotlin/jvm/internal/Intrinsics.checkParameterIsNotNull (Ljava/lang/Object;Ljava/lang/String;)V
L1
  LINENUMBER 16 L1
  ICONST_0
  IRETURN
L2
  LOCALVARIABLE bar Ljava/lang/String; L0 L2 0
  LOCALVARIABLE baz Ljava/util/List; L0 L2 1
  LOCALVARIABLE qux Ljava/util/Set; L0 L2 2
  MAXSTACK = 2
  MAXLOCALS = 3

生成的处理位掩码并在必要时计算默认值的包装器是一个单独的方法:

And the generated wrapper that handles the bit mask and calculates the default values if necessary is a separate method:

// access flags 0x1009
public static synthetic foo$default(
    Ljava/lang/String;
    Ljava/util/List;
    Ljava/util/Set;
    I
    Ljava/lang/Object;
)I
  ILOAD 3
  ICONST_2
  IAND
  IFEQ L0
L1
  LINENUMBER 16 L1
  INVOKESTATIC kotlin/collections/CollectionsKt.emptyList ()Ljava/util/List;
  ASTORE 1
L0
  ILOAD 3
  ICONST_4
  IAND
  IFEQ L2
  INVOKESTATIC kotlin/collections/SetsKt.emptySet ()Ljava/util/Set;
  ASTORE 2
L2
  ALOAD 0
  ALOAD 1
  ALOAD 2
  INVOKESTATIC FooKt.foo (Ljava/lang/String;Ljava/util/List;Ljava/util/Set;)I
  IRETURN
  MAXSTACK = 3
  MAXLOCALS = 5

请注意,后者如何检查位掩码(使用ILOAD 3ICONST_xIAND)然后有条件地(当IFEQ Lx不跳过它时)评估默认参数.

Note how the latter checks the bit mask (with ILOAD 3, ICONST_x, IAND) and then conditionally (when IFEQ Lx doesn't skip it) evaluates the default arguments.

构造函数与普通函数的不同之处在于它们的名称中不能带有后缀$default,因此标记是必需的,以避免可能的签名冲突.

Constructors are different from ordinary functions in that they can't have a suffix $default in the name, so the marker is necessary to avoid possible signatures conflict.

这篇关于Kotlin中默认构造函数中的两个其他类型?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆