为什么不要将属性初始化程序称为自定义setter?

时间:2016-12-19 00:51:02

标签: kotlin

Kotlin documentation,允许使用自定义设置器:

class Test {
  var stringRepresentation: String
    get() = field
    set(value) {
      setDataFromString(value) 
    }

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

但如果没有自定义getter(并从init块初始化),则无法拥有自定义setter:

class Test {
  // Compilation error: "Property must be initialized"
  var stringRepresentation: String
    set(value) {
      setDataFromString(value)
    }

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

虽然您可以使用没有自定义设置器的自定义getter,但这里没有问题:

class Test {
  var stringRepresentation: String
    get() = field 

  init {
    stringRepresentation = "test"
  }

  private fun setDataFromString(value: String) { }
}

那么为什么你不能在init块中使用带有属性初始化的自定义setter,为什么init块在属性初始值设定项直接赋值时调用自定义setter,绕过自定义setter?

class Test {
  var stringRepresentation: String = "" // Does not call custom setter
    set(value) {
      setDataFromString(value)
    }

  init {
    stringRepresentation = "test" // Calls custom setter
  }

  private fun setDataFromString(value: String) { }
}

1 个答案:

答案 0 :(得分:5)

属性初始值设定项不会调用自定义setter,因为它们的目的是提供默认值。

与Java不同,在Kotlin中,不仅必须在第一次访问之前初始化局部变量,还要对类属性进行初始化。

在Java中,这是有效的。

public class Test {
    public String str;

    public static void main(String[] args) {
        System.out.println(new Test().str);
    }
}

在Kotlin,这不是。

class Parent {
    var str: String?
}

fun main(args: Array<String>) {
    Parent().str
}

因此,自定义setter需要通过属性初始值设定项或构造函数初始化其属性。看一下下面的例子。

class Test {
    var stringRepresentation: String = "a" // Default value. Does not call custom setter
        get() = field
        set(value) {
            println("Setting stringRepresentation property to %s. Current value is %s.".format(value, field))
            field = setDataFromString(value)
        }

    init {
        this.stringRepresentation = "b" // Calls custom setter
    }

    private fun setDataFromString(value: String): String {
        println("Setting stringRepresentation property to %s.".format(value))
        return value
    }
}

fun main(args: Array<String>) {
    Test().stringRepresentation = "c" // Calls custom setter
}

属性stringRepresentation初始化为“a”其类的opon实例化而不调用setter。 然后调用init块并使用setter将值设置为“b”。 然后使用setter “c”