Home > Enterprise >  What's the best way to declare a constant in Kotlin?
What's the best way to declare a constant in Kotlin?

Time:12-14

When we using kotlin there are mainly two ways of declaring constant:

class Foo {
    companion object {
        private const val a = "A"
    }
}

And:

class Foo {
    private val a = "A"
}

which one is better?

I searched the companion way is equivalent to

public static final class Companion {
        @NotNull
             private static final String a = "A"; 
    }

in Java.

In this question

If a constant is not static, Java will allocate a memory for that constant in every object of the class (i.e., one copy of the constant per object).

If a constant is static, there will be only one copy of the constant for that class (i.e., one copy per class).

Yes that's true.

BUT If I have 100 or more constants in one class all static, when they are released? There are always in memory. They won't be released until the program killed/terminated, right?

So I think the second way

class Foo {
        private val a = "A"
    }

is the right way. As any instance will be released some point then the memory is released.

Not quite sure I missed something. Any comments? Thanks!

CodePudding user response:

BUT If I have 100 or more contacts in one class all static, when they are released?

You're going to write the info of 100 contacts in a source file? That's.. generally not where such data is supposed to go, but okay. 100.

You know what? That's bush league. Let's make it 10,000 contacts, all written out in one gigantic kotlin or java file.

It's still peanuts, memory wise. What's the share of a penny compared to the GDP of the world? Something along those lines. Whenever you load a class file, that's in memory. And is never getting released. And it doesn't matter one iota.

All those constant values are part of the class def and are loaded at least once in that sense no matter what you do.

The correct way is obviously for static data (i.e. things that are inherent to the class and do not ever change) to be loaded once precisely, instead of 'x times, where x is the amount of instances'. It's semantically correct (by its nature, unchanging, class-global stuff is static, that's what static means), and increments the 'load' of the fact that this class has been touched by a few percentage points (you're just adding references; all those strings are loaded only once and are loaded whether you make this stuff static or not, it's part of the class definition. Where do you imagine those strings go if there are 0 instances? JVM is not going to reload that class file from disk every time you call new Foo()!) - whereas if it's once-per-instance you might be looking at millions of refs for no reason at all.

CodePudding user response:

The ability to override makes a different between the two. Take a look at the following example. speed might be a property that is constant across a class, but you might want a different constant value for different subclasses.

import kotlin.reflect.KClass


open class Animal{
    
    companion object{
        val speed : Int = 1
    }
    
    var x: Int = 0
    
    fun move(){
        x  = speed
        print("${this} moved to ${x}\n")
    }
}

class Dog : Animal(){
    companion object{
        val speed : Int = 3
    }
}

class Cat : Animal(){
    companion object{
        val speed : Int = 2
    }
}

fun main()
{
    val a = Animal()
    a.move()
    val c = Cat()
    c.move()
    val d = Dog()
    d.move()
}

Output:

Animal@49c2faae moved to 1
Cat@17f052a3 moved to 1
Dog@685f4c2e moved to 1

This doesn't work because speed in move() always refer to Animal.speed. So in this case, you want speed be an instance member instead of static (or companion).

open class Animal{
    
    open val speed : Int = 1
    
    var x: Int = 0
    
    fun move(){
        x  = speed
        print("${this} moved to ${x}\n")
    }
}

class Dog : Animal(){
    override val speed : Int = 3
}

class Cat : Animal(){
    override val speed : Int = 2
}

Output:

Animal@37f8bb67 moved to 1
Cat@1d56ce6a moved to 2
Dog@17f052a3 moved to 3

As a general practice, if a value is something that is absolutely independent to individual instances, make it static. In contrast, if a property sounds like a property belongs to the individual instance, not belongs to a type, even it is constant across every instances (for the time being), I would put it as an instance member as it is likely subject to change in future development. Though it is totally fine to make it static until you actually find the needs to change in the future. For the above example, you might even eventually change speed to var instead of val when you later find that every individual dog has different speed. Just do what suit your needs at the moment :)

  • Related