【问题标题】:Getters and Setters in KotlinKotlin 中的 Getter 和 Setter
【发布时间】:2016-10-20 18:28:24
【问题描述】:

例如,在 Java 中,我可以自己编写 getter(由 IDE 生成)或在 lombok 中使用 @Getter 之类的注解 - 这非常简单。

然而,Kotlin 有 getters and setters by default。 但我不明白如何使用它们。

我想实现它,可以说 - 类似于 Java:

private val isEmpty: String
        get() = this.toString() //making this thing public rises an error: Getter visibility must be the same as property visibility.

那么 getter 是如何工作的呢?

【问题讨论】:

    标签: kotlin getter-setter


    【解决方案1】:

    Getter 和 setter 是在 Kotlin 中自动生成的。如果你写:

    val isEmpty: Boolean
    

    相当于下面的Java代码:

    private final Boolean isEmpty;
    
    public Boolean isEmpty() {
        return isEmpty;
    }
    

    在您的情况下,私有访问修饰符是多余的-默认情况下 isEmpty 是私有的,并且只能由 getter 访问。当您尝试获取对象的 isEmpty 属性时,您实际上调用了 get 方法。为了更深入地了解 Kotlin 中的 getter/setter:下面的两个代码示例是相同的:

    var someProperty: String = "defaultValue"
    

    var someProperty: String = "defaultValue"
        get() = field
        set(value) { field = value }
    

    我还想指出,getter 中的this 不是您的财产——它是类实例。如果您想在 getter 或 setter 中访问字段的值,可以使用保留字 field

    val isEmpty: Boolean
      get() = field
    

    如果您只想在公共访问中使用 get 方法 - 您可以编写以下代码:

    var isEmpty: Boolean
        private set 
    

    由于 set 访问器附近的 private 修饰符,您只能在对象内部的方法中设置此值。

    【讨论】:

    • In your case the private access modifier is redundant 怎么样? Kotlin 文档说默认修饰符是公开的。 kotlinlang.org/docs/reference/visibility-modifiers.html
    • @Nothing 是的,它看起来像公共字段,但在后台你调用 getter 方法
    • val isEmpty: Boolean 不会编译,因为 isEmpty 尚未初始化,对吧?刚开始学习 Kotlin。另外,get() = field 发生了什么?
    • 很好的解释,恕我直言,Kotlin 文档很难理解,除非您已经熟悉该语言...
    • 为什么 Kotlin 不更频繁地使用私有修饰符。似乎所有库的变量都是公开的。
    【解决方案2】:

    关于属性访问器visibility modifiers的规则如下:

    • varval 属性的 getter 可见性应该与属性的可见性完全相同相同,因此您只能显式复制属性修饰符,但这是多余的:

      protected val x: Int
          protected get() = 0 // No need in `protected` here.
      
    • var 属性的设置器可见性应与属性可见性相同或更少

      protected var x: Int
          get() = 0
          private set(x: Int) { } // Only `private` and `protected` are allowed.
      

    在 Kotlin 中,始终通过 getter 和 setter 访问属性,因此无需像在 Java 中那样使用 public 访问器创建属性 private -- its backing field (if present) 已经是私有的。因此,属性访问器上的可见性修饰符仅用于降低 setter 的可见性:

    • 对于具有支持字段和默认访问器的属性:

      var x = 0 // `public` by default
          private set
      
    • 对于没有支持字段的属性:

      var x: Int // `public` by default
          get() = 0
          protected set(value: Int) { }
      

    【讨论】:

    • 一套可以得到不同的类型吗?将x 设置为等于"Some String" 并返回字符串的长度11
    • @Carel,不,到目前为止,不支持此用例:属性的访问器应该与属性的类型完全一致。使用 separate backing property 涵盖了使用不同的类型
    • 该死,Kotlin 与 Python 非常接近,以至于当你被提醒输入它时,你认为它只会工作......然后割断你自己的喉咙。
    • 感谢访问修饰符。我从一个变量中删除了private,它可以从另一个带有getter的类中访问。
    • 当使用“var x//private set”组合时,我得到一个“Private setter are not allowed for open properties”。通过声明为“final var x”解决
    【解决方案3】:

    1) Kotlin 中 property firstName 的默认 settergetter 示例

    class Person {
        var firstName: String = ""
                get() = field       // field here ~ `this.firstName` in Java or normally `_firstName` is C#
                set(value) {
                    field = value
                }
    
    }
    

    使用

    val p = Person()
    p.firstName = "A"  // access setter
    println(p.firstName) // access getter (output:A)
    

    如果您的settergetter与上述完全相同,您可以将其删除,因为它不必要

    2) 自定义 setter 和 getter 示例。

    const val PREFIX = "[ABC]"
    
    class Person {
    
        // set: if value set to first name have length < 1 => throw error else add prefix "ABC" to the name
        // get: if name is not empty -> trim for remove whitespace and add '.' else return default name
        var lastName: String = ""
            get() {
                if (!field.isEmpty()) {
                    return field.trim() + "."
                }
                return field
            }
            set(value) {
                if (value.length > 1) {
                    field = PREFIX + value
                } else {
                    throw IllegalArgumentException("Last name too short")
                }
            }
    }
    

    使用

    val p = Person()
    p.lastName = "DE         " // input with many white space
    println(p.lastName)  // output:[ABC]DE.
    p.lastName = "D" // IllegalArgumentException since name length < 1
    

    更多
    我从 Java 开始学习 Kotlin,所以我对 fieldproperty 感到困惑,因为在 Java 中没有 property
    经过一番搜索,我看到 Kotlin 中的 fieldproperty 看起来像 C# (What is the difference between a field and a property?)

    这里有一些相关的帖子,讨论了 Java 和 Kotlin 中的 fieldproperty
    does java have something similar to C# properties?
    https://blog.kotlin-academy.com/kotlin-programmer-dictionary-field-vs-property-30ab7ef70531

    如果我错了,请纠正我。希望对你有帮助

    【讨论】:

    • 谢谢,对我很有帮助!
    【解决方案4】:

    kotlin 中的 Getter 默认是公共的,但您可以将 setter 设置为私有,并使用类中的一种方法设置值。像这样。

    /**
    * Created by leo on 17/06/17.*/
    
    package foo
    class Person() {
    var name: String = "defaultValue"
                   private set
    
    fun foo(bar: String) {
        name = bar // name can be set here
           }
    }
    
    fun main(args: Array<String>) {
      var p = Person()
      println("Name of the person is ${p.name}")
      p.foo("Jhon Doe")
      println("Name of the person is ${p.name}")
    }
    

    【讨论】:

      【解决方案5】:

      您可以查看本教程了解更多信息:

      Yet Another Kotlin Tutorial for Android Developers

      属性

      在 Kotlin 世界中,类不能有字段,只有属性。变量 关键字告诉我们属性是可变的,与 val 不同。让我们 看一个例子:

      class Contact(var number: String) {
      
         var firstName: String? = null
         var lastName: String? = null
         private val hasPrefix : Boolean
             get() = number.startsWith("+")
      
      }
      

      代码不多,但背后发生了很多事情 场景。 我们将逐步完成。首先,我们创建了一个 public final class 联系方式。

      这是我们必须面对的主要规则:如果没有另外指定, 默认情况下,类是公共的和最终的(顺便说一下,对于 类方法)。如果要从类继承,请将其标记为 open 关键字。

      【讨论】:

        【解决方案6】:

        如果你有一个 Var 那么你可以:

        var property: String = "defVal"
                      get() = field
                      set(value) { field = value }
        

        但是对于 Val,一旦赋值就不能设置,所以不会有 setter 块:

        val property: String = "defVal"
                      get() = field
        

        或者如果你不想要 setter,那么:

        val property: String = "defVal"
                      private set
        

        【讨论】:

        • 在从 Java 转换到 Kotlin 时要小心,因为 AI 引擎通常会将 Java 的 setter 和 getter 移动到 Kotlin 中自己的函数中,例如 getProperty()。这将导致各种错误。你需要实现阿里发布的解决方案。
        【解决方案7】:

        这是一个实用的、真实的 Kotlin getter 和 setter 示例(查看更多详细信息 here):

        // Custom Getter
        val friendlyDescription get(): String {
            val isNeighborhood = district != null
            var description = if (isNeighborhood) "Neighborhood" else "City"
            description += " in"
            if (isNeighborhood) {
                description += " $city,"
            }
            province?.let {
                if (it.isNotEmpty()) {
                    description += " $it,"
                }
            }
            description += " $country"
            return description
        }
        
        print(myLocation.friendlyDescription) // "Neighborhood in Denver, Colorado, United States"
        
        
        // Custom Setter
        enum class SearchResultType {
            HISTORY, SAVED, BASIC
        }
        
        private lateinit var resultTypeString: String
        
        var resultType: SearchResultType
            get() {
                return enumValueOf(resultTypeString)
            }
            set(value) {
                resultTypeString = value.toString()
            }
        
        result.resultType = SearchResultType.HISTORY
        print(result.resultTypeString) // "HISTORY"
        
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-11
          • 1970-01-01
          相关资源
          最近更新 更多