Kotlin中声明常量的最优方式:伴生对象还是类成员?
Kotlin两种常量声明方式的优劣分析
两种写法的本质区别
- 伴生对象中的
const val:对应Java的静态常量,属于类本身,全局仅存在一份实例,类加载时初始化,直到类被卸载才会释放(类卸载条件苛刻,通常程序运行期间会一直存在)。 - 类成员的
private val:属于类的每个实例,每个对象都会持有一个对常量的引用,实例被GC回收时,这个引用会被释放。
纠正内存认知误区
你提到的“非静态常量会在每个对象中分配内存”需要补充:对于字符串字面量(比如例子中的"A"),它本身会被存入字符串常量池,所有引用它的对象都是指向常量池中的同一个实例。也就是说,实例成员的val a = "A"并不会为字符串本身分配新内存,只是每个实例多了一个8字节左右的引用(64位系统),字符串本体的内存占用是共享的。
而伴生对象的静态常量,同样是引用常量池中的字符串,只是这个引用属于类,全局唯一。
选择建议
- 语义优先:如果常量是类级别的通用配置、固定参数,和实例无关,优先用伴生对象的
const val——这能明确表达“这是属于整个类的常量”的语义,即使是private修饰,代码可读性也更强。 - 实例关联场景:如果常量的值和实例强绑定(比如每个实例的常量值由构造参数决定),那必须用类成员的
val。 - 内存考量:
- 如果你的类会被创建大量实例(比如十万级以上),实例成员的引用总内存可能需要考虑,这时用静态常量更节省内存。
- 如果只是普通场景,少量实例,两种方式的内存差异可以忽略,没必要为了这点差异牺牲语义清晰度。
关于静态常量的内存驻留
你担心“100个以上静态常量会一直驻留内存”——实际上,字符串常量本身在常量池里是复用的,即使有100个不同的字符串,它们的总内存也只是这些字符串的字节数之和,而静态引用的内存开销微乎其微。只有当常量是大型对象(比如大数组、复杂对象)时,才需要考虑驻留内存的问题,普通字符串常量完全不用过度担心。
内容的提问来源于stack exchange,提问作者William Hu
相关产品推荐
相关产品推荐

