android-Kotlin中默认构造函数中的两个其他类型?

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

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

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

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

提前致谢.

解决方法:

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

使用Java反射,您可以通过检查isSynthetic()并查找不存在的函数来构造这些合成函数和构造函数.

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

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

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

如果检查此类函数的字节码,则对于函数声明,您将大致找到以下内容

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

字节码中的实际方法是:

// 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

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

// 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 3,ICONST_x,IAND),然后有条件地(当IFEQ Lx不跳过它时)评估认参数.

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

相关文章

Android性能优化——之控件的优化 前面讲了图像的优化,接下...
前言 上一篇已经讲了如何实现textView中粗字体效果,里面主要...
最近项目重构,涉及到了数据库和文件下载,发现GreenDao这个...
WebView加载页面的两种方式 一、加载网络页面 加载网络页面,...
给APP全局设置字体主要分为两个方面来介绍 一、给原生界面设...
前言 最近UI大牛出了一版新的效果图,按照IOS的效果做的,页...