2

我们有两个项目,其中一个 kotlin 发布了一个由 java 导入的包。

在 kotlin 中,是一个类似的值类

@JvmInline
value class CountryId(private val id: UUID) {
    override fun toString(): String = id.toString()
    companion object { fun empty(): CountryId = CountryId(EMPTY_UUID) }
}

在java中,我们看不到构造函数,或者实际实例化这个类。我也尝试在 Kotlin 中创建工厂来创建它们

class IdentifierFactory 
{
    companion object {
        fun buildString(): String {
            return "hello"
        }

        fun buildCountry(): CountryId {
            return CountryId.empty()
        }
    }
}

在java中,我可以调用IdentifierFactory.Companion.buildString()它并且它会工作,但IdentifierFactory.Companion.buildCountry()甚至不存在。

Java 的 Value 类真的这么糟糕吗?

附言。我也尝试过@JvmStatic,但没有成功

pps。如果我从 java 端反编译 kotlin 字节码,得到 CountryId.decompiled.java,这就是构造函数的样子

// $FF: synthetic method
private CountryId(UUID id) {
    Intrinsics.checkNotNullParameter(id, "id");
    super();
    this.id = id;
}

购买力平价。Kotlin 1.5.21 和 Java 12

4

1 回答 1

2

Java 的 Value 类真的这么糟糕吗?

值类是 Kotlin 的一个特性。它们基本上是糖,以允许更多的类型安全(在 Kotlin 中!),同时通过拆箱内部值来减少分配。字节码中存在类的事实CountryId主要是因为某些实例在某些情况下需要装箱(当用作泛型类型、超类型或可空类型时——简而言之,有点像原语)。但从技术上讲,它并不是真的要从 Java 方面使用。

在 java 中,我可以调用 IdentifierFactory.Companion.buildString() 并且它会工作,但 IdentifierFactory.Companion.buildCountry() 甚至不存在。

默认情况下,签名中带有值类的函数有意在 Java 中不可见,以避免在 Java 中出现奇怪的重载问题。这是通过name mangling完成的。@JvmName您可以通过在 Kotlin 端的工厂函数上使用注释来覆盖 Java 方法的名称,以使其在 Java 中可见:

@JvmName("buildCountryUUID") // prevents mangling due to value class
fun buildCountry(): CountryId {
    return CountryId.empty()
}

然后它可以在 Java 端访问并返回一个UUID(内联值):

UUID uuid = IdentifierFactory.Companion.buildCountryUUID();

理想情况下,我只想让构造函数工作而不使用工厂

我从评论中意识到您是在CountryId从 Java 创建实际实例之后。使用CountryIdJava 的构造函数对我来说很好:

CountryId country = new CountryId(UUID.randomUUID());

但我不确定这是怎么可能的,因为生成的构造函数在字节码中是私有的......

于 2021-11-10T22:44:51.090 回答