5

Let's say we have an object such as

object MyConstants {
   const val ONE: String = "One"
}

The generated bytecode resembles

public final class MyConstants {
   @NotNull
   public static final String ONE = "One";
   public static final MyConstants INSTANCE;

   private MyConstants() {}

   static {
      MyConstants var0 = new MyConstants();
      INSTANCE = var0;
   }
}

Is there a way to avoid generating the INSTANCE field while maintaining the same code layout? That means accessing fields through class both in Kotlin and Java

MyConstants.ONE
LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • 1
    Try to annotate it with @JvmStatic – RadekJ Mar 14 '20 at 19:17
  • @RadekJ Doesn't work. I've tried with multiple combinations but can't get rid of that **unneeded** instance, and thus unneeded object allocation. – LppEdd Mar 14 '20 at 19:18
  • 2
    Well, that's the implementation of `object`. It implies creating an object that you can use just like any other object. An object without instance is a contradiction. You can use top-level constants if you don't want an object. The `MyConstants.CONSTANT` smells like Java to me, as this "pattern" was an effect of the language forcing you to put everything inside classes – gpunto Mar 14 '20 at 20:02
  • @gpunto even with a class and a companion object it's the same. And I want clear wrapping and accessing to the constants, that's why. – LppEdd Mar 14 '20 at 20:16
  • @LppEdd I guess you've already tried, but what about creating a plain Kotlin file with `const val ONE = "One` as its only content? – user2340612 Mar 14 '20 at 20:28
  • as for the companion object, if you make it `private` it won't generate any `Companion` static field (actually there's a bug that generates it anyway, but it will be solved in Kotlin 1.4. More details here: https://youtrack.jetbrains.com/issue/KT-11567) – user2340612 Mar 14 '20 at 20:31
  • @user2340612 but then I can't access via class name in Kotlin. – LppEdd Mar 14 '20 at 20:36
  • @LppEdd sorry in advance - I do not know how to address your issue with solution satisfying your demands. I'm curious however as to why does the presence of the 'instance' reference in the bytecode bother you so much? I understand certain redundancy of it in your case, but this smells like high overreaction in memory-management department. – ryfterek Mar 15 '20 at 20:08
  • @ryfterek Don't worry, I understand what you mean. However that instance is static and will live (most probably) for the entire VM lifecycle. Yeah, I'm over-optimizing for sure, but I don't like having non-requested or non-needed bytecode, that's why – LppEdd Mar 16 '20 at 09:38

3 Answers3

2
object MyConstants {
@JvmStatic
 val ONE: String = "One"
}

@JvmStatic will not use the INSTANCE

Mohmmaed-Amleh
  • 383
  • 2
  • 11
0

try something like this:

class MyConstants {
    companion object {
        const val ONE: String = "One"
    }
}

class Test {

    fun test(){
       System.out.println(MyConstants.ONE) 
    }
}
SwaiX
  • 79
  • 1
  • 5
0

It seems you need something like this:

@file:JvmName("Constantestest")
package com.grupomacro.macropay.models

const val A = 1
const val B = 2

From java, these are accessed just as:

int a = Constantestest.A;

And the INSTANCE reference is not available anymore.

Check the answer to this related question: Hiding Kotlin object's INSTANCE field from Java (and Kotlin)

Jesús Barrera
  • 400
  • 1
  • 5
  • 15