【问题标题】:Mark a fun / property for use in Kotlin / Java only标记一个 fun / 属性以仅在 Kotlin / Java 中使用
【发布时间】:2020-06-19 15:08:45
【问题描述】:

我目前正在编写一个 KOTLIN 类,如果我喜欢使用 DSL 的可能性,但要向后兼容 JAVA 开发人员。使用 var 时,编译器会自动为 JAVA 创建 getter 和 setter,但不能使用 Builder 样式,因为它们没有返回 this

所以基本上我喜欢做的事情是这样的:

class MyClass {
    // for use in KOTLIN only DSL style e.g. MyClass() { offset = 1 }
    var offset: Int? = null

    // for use in JAVA only BUILDER style e.g. new MyClass().withOffset(1)
    fun withOffset(value: Int) = apply { offset = value }
}

我喜欢在 Kotlin 中使用,但不想访问 withOffset 乐趣:

val myClass = MyClass() { offset = 1 }

我喜欢在JAVA中使用,但不想访问自动创建的setOffsetgetOffset

MyClass myClass = new MyClass().withOffset(1)

已经可以通过@JvmName 注解重命名getter 和setter,但是是否有一个注解可以完全隐藏JAVA 的公共属性,当然反之亦然?

【问题讨论】:

    标签: java kotlin annotations backwards-compatibility


    【解决方案1】:

    您不能隐藏构造函数,但您可以使用 operator fun invoke 制作所谓的假构造函数,在其中您可以使用 @JvmSyntheic 注释将其隐藏在 java 中。

    要对 kotlin 隐藏函数,您可以使用 @DeprecatedDeprecationLevel.HIDDEN

    注意:@JvmField 将指示编译器不要为您的 var 生成默认的 getter 和 setter

    class MyClass {
        @JvmField
        var offset: Int? = null
    
        @kotlin.Deprecated(message = "JUST FOR JAVA", level = DeprecationLevel.HIDDEN)
        fun withOffset(value: Int) = apply { offset = value }
    
        companion object {
            @JvmSynthetic
            operator fun invoke(init: MyClass.() -> Unit) = MyClass().apply(init)
        }
    }
    

    在 kotlin 中的用法:

    MyClass() { offset = 1 }
    // or
    MyClass { offset = 1 }
    

    在java中的用法:

    MyClass().withOffset(1)
    

    资源:

    【讨论】:

    • 感谢您的快速回答。不推荐使用的方法似乎不再起作用。您提供的参考资料中也提到了这一点。还有一个提到的技巧确实有效@kotlin.SinceKotlin(version = "99999.0") ...不确定我是否应该使用它。无论如何,躲避 Kotlin 并不是那么重要。我现在将尝试@JvmSynthetic。会告诉你它是否有效。
    • @tekgator Deprecated 仍然有效,使用 Kotlin1.4-M1 进行测试。看到它在操场上显示 Unresolved reference 以及 1.3.72 pl.kotl.in/Qjc5_WM4i
    • 对不起,可能是误导性的评论。事实上,它在 Kotlin 中隐藏了它,但在 Java 中也是如此。错误 = 需要方法调用,就像方法根本不存在一样
    【解决方案2】:

    在 Kotlin 中不可能做这样的事情

    val myClass = MyClass() { offset = 1 }
    

    但我建议你这样做,我认为它看起来更好。

    // It's a inline function so there's no runtime overhead.
    inline fun buildMyClass(builder: MyClass.() -> Unit): MyClass {
        return MyClass().apply(builder)
    }
    
    class MyClass {
    
        @JvmSynthetic
        var offset: Int? = null
            private set
    
        fun withOffset(value: Int) = apply { offset = value }
    }
    

    所以你可以像下面这样称呼它

    val myClass = buildMyClass {
       withOffset(0)
    }
    

    在 Java 中,它看起来像这样:

    final MyClass myClass = new MyClass().withOffset(0);
    

    【讨论】:

    • MyClass() { offset = 1 } 是可能的,如果您像在 buildMyClass 中所做的那样在构造函数中接受接收器 lambda
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-09-20
    • 1970-01-01
    • 2021-08-16
    • 2017-12-22
    • 2021-06-07
    • 1970-01-01
    • 2019-06-06
    相关资源
    最近更新 更多