Java 中的 Kotlin 内部 类 公开可见

Kotlin internal classes in Java visible publicly

我正在文档中开发 Android crypto library in Kotlin. I have a couple of internal classes which become publicly visible in a Java app. Found this

internal declarations become public in Java. Members of internal classes go through name mangling, to make it harder to accidentally use them from Java and to allow overloading for members with the same signature that don't see each other according to Kotlin rules;

有办法解决这个问题吗?

你的internal classes are all about encrypt & decrypt我都看过了。

您可以通过定义一个顶级函数并将其标记为 @JvmSynthetic,然后将 ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类 设为 private防止Java客户端访问你的内部类,例如:

// define this top-level function in your ECryptSymmetricEncrypt.kt

@JvmSynthetic internal fun <T> encrypt(
                                       input:T, password: String, cipher:Cihper, 
                                       erl: ECryptResultListener, outputFile:File,
                                       getKey:(String,ByteArray)->SecretKeySpec){

  ECryptSymmetricEncrypt(input, password, cipher,
                { pass, salt -> getKey(pass, salt) }, erl, outputFile)
}

但是,它解决了你的问题,但我仍然想说你的代码可以进一步分解成小块。例如,加密和解密算法有很多重复,也许你可以在你的加密库中应用 Template Method Pattern 并引入接口来明确地使你的库和隐藏 Cipher 实现下的操作 类 .理想情况下,客户端代码无法通过 EncryptDecrypt 接口看到任何 java.security.* 类。例如:

interface Encrypt{
   //          v--- don't include the infrastructure class here,e.g:`Keys`,`Cipher`
   fun encode(...args)
}

interface Decrypt{
   //          v--- don't include the infrastructure class here,e.g:`Keys`,`Cipher`
   fun decode(...args)
}

AND 创建实例并在 inithere 中计算结果是一件坏事。

AND 你可以使用 Factory Method Pattern to avoid the type checking both in ECryptSymmetricDecrypt and ECryptSymmetricEncrypt 类。

除了 @JvmSynthetic 之外,您还可以将 @JvmName 与非法的 Java 标识符一起使用,例如添加 space.

例如,我在 @JvmName 参数中添加了一个 space,因此除 Kotlin 之外的任何语言都无法调用您的方法:

@JvmName(" example")
internal fun example() {
}

根据我在 主题中对这个问题的回答:

不是完美的解决方案,但我发现了两个 hacky 解决方案

用空格或特殊符号注释 internal class 的每个 public 方法 @JvmName,这些方法会在 Java.[=29 中产生语法错误=]

例如

internal class LibClass {

    @JvmName(" ") // Blank Space will generate error in Java
    fun foo() {}

    @JvmName(" $#") // These characters will cause error in Java
    fun bar() {}
}

由于上述解决方案不适合管理大型项目或似乎不是很好的做法,因此以下解决方案可能会有所帮助。

通过 @JvmSynthetic 注释 internal class 的每个 public 方法,其中 Java 无法访问 public 方法。

例如

internal class LibClass {

    @JvmSynthetic
    fun foo() {}

    @JvmSynthetic
    fun bar() {}
}

注:

此解决方案保护了函数的 methods/fields。根据问题,它不会隐藏 Java 中 class 的可见性。所以还是期待完美的解决方案吧

利用私有构造函数 + 包含方法的伴随对象实例化 JvmSynthetic 注释保留封装。

// Private constructor to inhibit instantiation
internal class SomeInternalClass private constructor() {

    // Use the companion object for your JvmSynthetic method to
    // instantiate as it's not accessible from Java
    companion object {
        @JvmSynthetic
        fun instantiate(): SomeInternalClass =
            SomeInternalClass()
    }

    // This is accessible from Java
    @JvmSynthetic
    internal var someVariable1 = false

    // This is accessible from Java
    @JvmSynthetic
    var someVariable2 = false



    // This is inaccessible, both variable and methods.
    private var someVariable3 = false
    @JvmSynthetic
    fun getSomeVariable3(): Boolean =
        someVariable3
    @JvmSynthetic
    fun setSomeVariable3(boolean: Boolean) {
        someVariable3 = boolean
    }
}