java Kotlin 属性的私有 getter 和公共 setter

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/38243085/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-11-03 03:14:54  来源:igfitidea点击:

Private getter and public setter for a Kotlin property

javakotlinkotlin-interop

提问by Randy Sugianto 'Yuku'

How to make a property in Kotlin that has a private getter (or just do not have it) but has a public setter?

如何在 Kotlin 中创建具有私有 getter(或只是没有它)但具有公共 setter 的属性?

var status
private get

doesn't work with an error: Getter visibility must be the same as property visibility

不会出现错误: Getter visibility must be the same as property visibility

In my case, the reason is for Java interop: I want my Java code to be able to call setStatusbut not getStatus.

就我而言,原因是 Java 互操作:我希望我的 Java 代码能够调用setStatus但不能调用getStatus.

采纳答案by Alexander Udalov

It's impossible at the moment in Kotlin to have a property with a setter that is more visible than the property. There's a language design issue in the issue tracker on this, feel free to watch/vote for it or share your use cases: https://youtrack.jetbrains.com/issue/KT-3110

目前在 Kotlin 中不可能有一个属性的 setter 比属性更明显。问题跟踪器中存在一个语言设计问题,请随时观看/投票或分享您的用例:https: //youtrack.jetbrains.com/issue/KT-3110

回答by miensol

In current Kotlin version (1.0.3) the only option is to have separate settermethod like so:

在当前的 Kotlin 版本 (1.0.3) 中,唯一的选择是使用单独的setter方法,如下所示:

class Test {
    private var name: String = "name"

    fun setName(name: String) {
        this.name = name
    }
}

If you wish to restrict external libraries from accessing the getter you can use internalvisibility modifier allowing you to still use property syntax within the library:

如果您希望限制外部库访问 getter,您可以使用internal可见性修饰符,允许您仍然在库中使用属性语法:

class Test {
    internal var name: String = "name"
    fun setName(name: String) { this.name = name }
}

fun usage(){
    val t = Test()
    t.name = "New"
}

回答by TheOperator

Write-only properties with compile-time errors canbe achieved since Kotlin 1.0, using a workaround based on @Deprecated.

编译时错误只写性能可以因为科特林1.0来实现,使用基于一种变通方法@Deprecated

Implementation

执行

Kotlin allows to mark functions deprecated with level ERROR, which leads to a compile-time error when called. Annotating the getaccessor of a property as error-deprecated, combined with a backing field (so that private reads are still possible), achieves the desired behavior:

Kotlin 允许使用 level 标记不推荐使用的函数ERROR,这会在调用时导致编译时错误。get将属性的访问器注释为error-deprecated,结合支持字段(以便私有读取仍然可能),实现了所需的行为:

class WriteOnly {
    private var backing: Int = 0

    var property: Int
        @Deprecated("Property can only be written.", level = DeprecationLevel.ERROR)
        get() = throw NotImplementedError()
        set(value) { backing = value }

    val exposed get() = backing // public API
}

Usage:

用法:

val wo = WriteOnly()
wo.property = 20         // write: OK

val i: Int = wo.property // read: compile error
val j: Int = wo.exposed  // read value through other property

The compile error is quite helpful, too:

编译错误也很有帮助:

Using 'getter for property: Int' is an error. Property can only be written.

使用 'getter for property: Int' 是一个错误。属性只能写。



Use cases

用例

  1. The main use case are obviously APIs that allow properties to be written, but not read:

    user.password = "secret"
    val pw = user.password // forbidden
    
  2. Another scenario is a property which modifies the internal state, but is not stored itself as a field. (Could be done more elegantly using different design).

    body.thrust_force = velocity
    body.gravity_force = Vector(0, 0, 9.8)
    // only total force accessible, component vectors are lost
    val f = body.forces
    
  3. This pattern is also useful for DSLs of the following kind:

    server {
        port = 80
        host = "www.example.com"
    }
    

    In such cases, values are simply used as one-time settings, and the write-only mechanism described here can prevent accidentally reading a property (which might not be initialized yet).

  1. 主要用例显然是允许写入但不允许读取属性的 API:

    user.password = "secret"
    val pw = user.password // forbidden
    
  2. 另一种情况是修改内部状态的属性,但它本身不存储为字段。(可以使用不同的设计更优雅地完成)。

    body.thrust_force = velocity
    body.gravity_force = Vector(0, 0, 9.8)
    // only total force accessible, component vectors are lost
    val f = body.forces
    
  3. 此模式对于以下类型的 DSL 也很有用:

    server {
        port = 80
        host = "www.example.com"
    }
    

    在这种情况下,值仅用作一次性设置,此处描述的只写机制可以防止意外读取属性(可能尚未初始化)。



Limitations

限制

Since this feature was not designed for this use case, it comes with certain limitations:

由于此功能不是为此用例设计的,因此具有某些限制:

  • If accessed using a property reference, the compile-time error turns into a runtime error:

    val ref = wo::property
    val x = ref.get() // throws NotImplementedError
    
  • The same is true for reflection.

  • This functionality cannot be outsourced into a delegate, because an error-deprecatedgetValue()method cannot be used with by.

  • 如果使用属性引用访问,编译时错误会变成运行时错误:

    val ref = wo::property
    val x = ref.get() // throws NotImplementedError
    
  • 反射也是如此。

  • 此功能不能外包给委托,因为错误弃用的getValue()方法不能与by.