简体   繁体   中英

Converting a generic enum from Java to Kotlin

I am currently trying to translate a small application from java to kotlin without having to rewrite everything, however i am facing problems with a generic enum, since kotlin doesn't support generics in enums.

I have the following enum in java:

public enum Property {
    LAST_VIEW(0, 1, Integer.class),
    MAXIMIZED(2, false, Boolean.class),

    private final int       id;
    private final String    defaultValue;
    private final Class<?>  datatype;

    <T> Property(final int id, final T defaultValue, final Class<T> datatype) {
        this.id = id;
        this.defaultValue = defaultValue == null ? null : defaultValue.toString();
        this.datatype = datatype;
    }
}

I am using this for a generic properties api in order to verify that my default values have the correct type and also do some runtime checks in order to give proper feedback as soon as i am making a mistake.

Is there anyways to make such a class in kotlin or should i consider refactoring my properties api instead?

Perhaps you could consider sealed classes for this, rather than an enum?

sealed class Property<T>(val id: Int, val defaultValue: T, dataType: Class<T>) 
object LastView : Property<Int>(0, 1, Int::class.java)
object Maximised : Property<Boolean>(2, false, Boolean::class.java)

In this case because LastView and Maximized don't have any user-defined or mutable state, I've defined them as objects . And because Property<T> is sealed, no other instances can be created.

While Kotlin does not allow constructors to have their own type parameters, this feature in Java only affects type checking of the constructor arguments at call sites (the enum entries don't retain the type safety). So it's possible to achieve similar behavior in Kotlin by declaring a helper generic class and accepting its instance in a secondary constructor:

class TypedDefaultValue<T>(
    val defaultValue: T,
    val datatype: Class<T>
)

enum class Property(
    val id: Int, 
    val defaultValue: Any, 
    val datatype: Class<out Any>
) {
    LAST_VIEW(0, TypedDefaultValue(1, Int::class.java)), // calls the constructor below
    MAXIMIZED(2, TypedDefaultValue(false, Boolean::class.java));

    constructor(id: Int, typedDefaultValue: TypedDefaultValue<out Any>) :
        this(id, typedDefaultValue.defaultValue, typedDefaultValue.datatype)
}

Use Any? and out Any? in the enum code to accept nullable values as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM