了解Kotlin构造函数和超类型初始化

时间:2020-05-27 20:43:47

标签: android kotlin

我上了这个课:

class MyClass: Fragment(), AdapterView.OnItemSelectedListener {
    companion object {
        fun newInstance(parent: Activity) = MyClass(parent)
    }

    constructor(parent: Activity) {
        this.parent = parent;
    }

在Fragment()上给出错误的地方:

没有主构造函数就无法进行超类型初始化

然后我跟随Supertype initialization is impossible without primary constructor并更改为

class MyClass constructor(): Fragment(), AdapterView.OnItemSelectedListener {
    companion object {
        fun newInstance(parent: Activity) = MyClass(parent)
    }

    constructor(parent: Activity) {
        this.parent = parent;
    }

但是后来我得到了

这个主意使我改变为

    constructor(parent: Activity) : this() {
        this.parent = parent;
    }

constructorclass MyClass constructor(): Fragment()意味着什么?为什么我必须放一个this()

1 个答案:

答案 0 :(得分:3)

来自the documentation

Kotlin中的类可以具有一个主构造函数和一个或多个辅助构造函数。主要构造函数是类标题的一部分:它位于类名称(和可选的类型参数)之后。

这是主要构造函数的示例:class MyClass constructor()

仅当您要指定可见性修饰符(default is public)和/或注释时,才必须使用关键字constructor,因此以下所有替代方法都是等效的:

class MyClass public constructor()
class MyClass constructor()
class MyClass()
class MyClass // parenthesis can be omitted if no argument is provided

如果您要使用的是那种构造函数,那么显然,较简洁的版本胜于更冗长的版本。

除了主要构造函数之外,您还可以具有零个,一个或多个辅助构造函数。辅助构造函数必须通过调用另一个辅助构造函数直接或间接委托给主要构造函数-示例:constructor(...) : this(...)

如果您的类未指定任何主构造函数,则任何辅助构造函数都必须委托给超类。范例:例如constructor(...) : super(...)

如果您未指定任何主构造函数或辅助构造函数,则您的类将具有不带任何参数的隐式默认公共构造函数(如Java中一样)。

所以,回答您的问题:

constructorclass MyClass constructor(): Fragment()意味着什么?

它声明了主要的构造函数,但是鉴于您没有指定任何可见性修饰符,也没有任何注释,因此可以省略它。括号也是如此,因此可以将其重写为class MyClass : Fragment()(注意: Fragment()位声明您的类扩展了Fragment,并指定了MyClass的默认构造函数应调用其父级的空构造函数(更多详细信息here

为什么我必须放一个this()? 如上所述,这对于辅助构造函数是必需的。


编辑

如下面我的评论中所述,在第一段代码中,您是:

  • 定义辅助构造函数(constructor(parent: Activity)
  • 未定义主要构造函数。那是因为您有一个辅助构造函数,但是在类定义之后没有括号(即class MyClass()class MyClass constructor()-如上所述,它们是等效的),因此Kotlin不会为你
  • 您的课程正在扩展Fragment,并且您正在调用父级的构造方法作为您课程签名的一部分。 需要您的班级的主要构造函数,如您所面临的错误所突出显示:Supertype initialization is impossible without primary constructor

如何解决问题?

一种可能的方法是完成工作,即定义一个主构造函数和一个辅助构造函数。但是,您将可以通过两种方式创建MyClass的实例:传递或不传递父活动。这大致等效于以下Java代码:

class MyClass extends Fragment {
    private Activity parent;

    public MyClass() {
        super()
    }

    public MyClass(Activity parent) {
        super()
        this.parent = parent;
    }
}

可能您不希望在没有父Activity的情况下构造该类。如果是这种情况,只需摆脱辅助构造函数(您不需要它),然后创建一个接受所需参数的主要构造函数。 示例:class MyClass(val parent: Activity) : Fragment()。这是定义主构造函数的一种非常简洁的方法,该构造函数接受输入中的Activity并将该参数分配给名为parent的实例变量; val表示parent将是只读的(即Kotlin会生成一个getter而不是setter),但是如果您需要实例变量是可变的,则可以使用var(例如Kotlin会同时生成一个getter和setter)。

这大致等效于以下Java代码:

class MyClass extends Fragment {
    private Activity parent;

    public MyClass(Activity parent) {
        this.parent = parent;
    }
}
相关问题