如何在 Kotlin 中访问枚举属性和函数

5
以下枚举定义是有效的。能否访问“内部属性”auditData或函数auditor?
enum class GWGStatus {
    UNCHECKED,
    CHECKED {
        lateinit var auditDate: Date
        fun auditor() : String = "Peter"
    }
}

GWGStatus.CHECKED.??? (does not work)

GWGStatus 中声明它们并重载或创建接口并实现它。参考- https://stackoverflow.com/questions/10055848/java-access-enum-specific-methods - Gurupad Mamadapur
3个回答

4
一看到这个,我就需要查找字节码,因为我无法想象这应该如何翻译。虽然我认为“it”是一个错误,但我会向您展示我迄今为止发现的内容。
对于“CHECKED”,实际上创建了它自己的子类,即“public final class GWGStatus$CHECKED extends GWGStatus”,尽管“GWGStatus”本身是一个枚举。可能是JVM字节码中允许的东西,但在Java语言规范中不允许。
现在是不太一致的部分。虽然以下代码在Java中可以工作:
GWGStatus.CHECKED status = (GWGStatus.CHECKED) GWGStatus.CHECKED;
status.auditDate = new Date();
System.out.println(status.auditor());

并且如预期一样打印出Peter,但是在Kotlin中还不能进行此转换(尚未支持?):

GWGStatus.CHECKED as GWGStatus.CHECKED // fails: Use of enum entry names as types is not allowed, use enum type instead

现在在Kotlin中使用Java反射工具(例如status :: class.java.declaredFields或 .java.declaredMethods ),可以让auditor()和getAuditDate()等都可见且可访问(正如Java代码本身已经证明的那样)。进一步分析并仅使用Kotlin反射:
GWGStatus.UNCHECKED::class // returns class GWGStatus
GWGStatus.CHECKED::class // return class GWGStatus$CHECKED ... that's good so far
GWGStatus.CHECKED::class.declaredMembers // empty list ... didn't expect this one
// empty too: GWGStatus.CHECKED::class.declaredMemberProperties
// and GWGStatus.CHECKED::class.declaredFunctions
GWGStatus.CHECKED::class.superTypes // shows GWGStatus as expected
GWGStatus.CHECKED::class.members // shows clone(), finalize(), name, equals, hashcode, tostring, getdeclaringclass, ordinal... nothing we are interested in and rather the ~general enum members
GWGStatus::class.nestedClasses // empty too

好的...我们无法使用Kotlin反射来查看它们(或许我没有使用正确的方法?;-))。所以:这里有一些味道像是一个bug,但我还不确定哪个是:

  1. 是不应该在第一时间创建一个子类吗?
  2. 子类是否应该在Kotlin本身中可访问和可见?
  3. Kotlin编译器是否应该抱怨这个问题,因为这还不是一个完整的特性?
  4. 实际上错误消息是错误的,它只应该允许强制类型转换吗?
  5. 其他原因?

“但是在Java语言规范中是不允许的。” - 就像您自己的例子中展示的那样,它能够在Java中工作,这表明它是符合Java语言规范的。 - Logan Pickup
1
仅仅因为某个东西能够工作,并不意味着它就是规定的方式... 如果你在Java语言规范中找到了相关内容,请分享链接... - Roland

3
你需要在enum类型中声明变量和函数,然后在enum实例中覆盖它们。
不幸的是,由于并非所有enum实例都实现了该函数,因此无法将其设置为abstract,必须提供默认实现:
import java.util.*

enum class GWGStatus {
    UNCHECKED,
    CHECKED {
        override lateinit var auditDate: Date
        override fun auditor(): String = "Peter"
    };

    open lateinit var auditDate: Date
    open fun auditor(): String = ""
}

fun main(vararg args: String) {
    GWGStatus.CHECKED.auditDate = Date()

    println(GWGStatus.CHECKED.auditDate)
    println(GWGStatus.CHECKED.auditor())
}

注意,这种 enum 的用法会感觉非常奇怪。你正在将状态数据存储在旨在成为常量对象的东西中。内存中只会有一个 GWGStatus.CHECKED 对象,因此似乎不是存储状态信息的正确位置。


0

你也可以直接使用构造函数:

enum class GWSGStatus(var date: Date, private var auditor: String) {
    UNCHECKED(Date(), ""),
    CHECKED(Date(), "Peter");

    fun auditor() = auditor
}

它仍然取决于此枚举的用法。请注意以前的帖子


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接