简体   繁体   中英

Java private static final field and anonymous inner classes vs. Kotlin const val and object expressions/declarations

Let's say I have a Kotlin interface:

interface Dog {
    fun walk()
}

I want to create an Kotlin object of this class with slight modifications , like so:

val poodle : Dog = object : Dog {

    override fun walk() {
        ...
    }
}

However, I also want to add a what is equivalent to a private static final field in Java to this object, like so ( this is a working example in Java ):

Dog poodle = new Dog() {

    private static final String POODLE_FASHION = ...

    @Override
    public walk() {
        ...
    }
}

I read that a private const val is equivalent to this in Kotlin. I tried to do the following (this is an example in Kotlin that is NOT working) :

val poodle : Dog = object : Dog {

    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

When I did this, I got the following error in Android Studio: Const 'val' are only allowed on top level or in objects .

Could someone explain why the Java version works, but the Kotlin version doesn't? How do I do this for Kotlin (I tried companion object already, but got the error Modifier 'companion' is not applicable inside 'local class' )? Note I don't want to do the following because I want POODLE_FASHION to live inside val poodle as I am going to create other Dog objects with slight modification as well ( val pug , val chihuahua , etc.):

private const val POODLE_FASHION = ...

val poodle : Dog = object : Dog {

    override fun walk() {
        ...
    }
}

Thanks!

val poodle : Dog = object : Dog {

    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

In this example, there's really no reason at all POODLE_FASHION needs to be static or const. It can just be a normal val , and it won't cost you anything extra.

That said, it sounds like you ought to have a Poodle class, not an object.

Note the difference between an object expression and an object declaration.

  • val poodle = object: Dog { ... } is an object expression . It creates an anonymous object. It's the equivalent of writing Dog poodle = new Dog() { ... } in Java.
  • object Poodle: Dog { ... } is an object declaration . It creates a singleton object, and is roughly equivalent to creating a Java class that is limited to only having one instance.

The Kotlin documentation states that const val properties must be "top-level, or member of an object declaration or a companion object." ( https://kotlinlang.org/docs/reference/properties.html#compile-time-constants ). They are not valid in object expressions.

The following object declaration should work fine:

object Poodle : Dog {
    private const val POODLE_FASHION = ...

    override fun walk() {
        ...
    }
}

One important reason for the distinction is that an object expression doesn't declare a new type (though, in Java terms, it does result in an anonymous class).

  • val poodle = object: Dog { ... } creates a variable of type Dog . There is no such type as Poodle .
  • object: Poodle: Dog { ... } creates an object of type Poodle . This is a new type which is a subtype of Dog .

This difference is important, because in Kotlin a const val property always belongs to a type. MyClass.MY_CONST_VAL is valid, but accessing it as MyClass().MY_CONST_VAL is an error and would not work. As a result, a const val property on an anonymous object would always be effectively private to that object.

I can't see a technical reason why it wouldn't be possible to allow const val properties on anonymous objects ( static final compile-time constant fields are allowed in Java inner classes), but their usefulness would be severely limited and it just isn't part of the Kotlin language spec.

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