在实现 Java 接口时如何克服“相同的 JVM 签名”错误?

通过下面的代码,我在 IntelliJ IDEA 13.1.6和 Kotlin 插件0.11.91中得到了以下错误:

Platform declaration clash: The following declarations have the same JVM signature (getName()Ljava/lang/String;):
• public open fun getName(): kotlin.String?
• internal final fun <get-name>(): kotlin.String?

Java 类,JavaInterface.java:

public interface JavaInterface {
public String getName();
}

科特林级,KotlinClass.kt

public class KotlinClass(val name: String?) : JavaInterface

我已经尝试通过以下方法重写“ getter”方法 添加 override fun getName(): String? = name,但会产生相同的错误。

我可以想出一个解决办法:

public class KotlinClass(val namePrivate: String?) : JavaInterface {
override fun getName(): String? = namePrivate
}

但是在我的实际情况中,我需要实现许多属性,并且也需要 setter。对每个属性都这样做似乎不太像科特林风格。我错过了什么?

30917 次浏览

另一个解决方法是在一个抽象 Kotlin 类中声明属性,然后编写一个扩展 KotlinClass 并实现 JavaInterface 的小 Java 类。

// JavaInterface.java
public interface JavaInterface {
int getFoo();
void setFoo(int value);
}


// KotlinClass.kt
abstract class KotlinClass(open var foo : Int = 0) {
}


// JavaAdapter.java
class JavaAdapter extends KotlinClass implements JavaInterface {
// all code in KotlinClass, but can't implement JavaInterface there
// because kotlin properties cannot override java methods.
}

使变量 private解决了这个问题。

public class KotlinClass(private val name: String?) : JavaInterface

public interface JavaInterface {
public String getName();
}


public class KotlinClass(val namePrivate: String?) : JavaInterface {


private var name = namePrivate


override fun getName(): String? {
return name
}
}

我们发现,要使用相同的名称而不发生冲突,ctor 参数必须是 二等兵 还有,而接口方法必须是 仍然重写。您不需要任何 附加费后台字段。另外,表达式主体的赋值不会递归,因此可以安全地使用该语法。

Java 接口

interface IUser {
String getUserScope();
String getUserId();
}

科特林班

class SampleUser(private val userScope: String, private val userId: String) : IUser {
override fun getUserId() = userId
override fun getUserScope() = userScope
}

您可以使用@JvmField 来指示编译器不生成 getter/setter,并且您可以实现您的 setter 和 getter。这样,您的代码在 Java (作为属性 getter/setter)和 Kotlin (作为属性)中工作得很好

例如: JAVA :

public interface Identifiable<ID extends Serializable>
{
ID getId();
}

KOTLIN :

class IdentifiableImpl(@JvmField var id: String) :Identifiable<String>
{
override fun getId(): String
{
TODO("not implemented")
}
}

如果你可以直接控制界面,那么最好的方法就是在 Kotlin 编写界面。然后您可以编写您的类

public class KotlinClass(override val name: String?) : KotlinInterface

并且仍然使用与前面相同的接口从任何 Java 代码引用它。这看起来比将所有属性设置为 private 并重写 get 函数要简单得多。显然,如果你不能将接口迁移到 Java,因为你不拥有它,那么这似乎是唯一的解决方案。

恕我直言,最易读的组合是字段 + 单表达式函数的显式接口实现(@Renato Garcia 和@Steven Spungin 的回答组合) :

Java:

public inteface SomeInterface {
String getFoo();
}

科特林:

class Implementation(@JvmField val foo: String) : SomeInterface {
override fun getFoo() = foo
}

将变量重命名为其他名称,或者如果您不希望变量为公共,则将其设置为私有。

Kotlin 的标注功能名为 @JvmName,可以解决 Java 和 Kotlin 使用相同签名时的复制问题。

fun function(p: String) {
// ...
}


// Signature: function(Ljava/lang/String)

使用 JvmName将会:

@JvmName("functionOfKotlin")
fun function(p: String) {
// ...
}


// Signature: functionOfKotlin(Ljava/lang/String)

将函数转换为属性,而不是从函数初始化属性。 例如:

    fun getCountriesList(): List<Country> {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States",R.drawable.us_flag))
return countries
}

 val countriesList: List<Country>
get() {
val countries = mutableListOf<Country>()
countries.add(Country("in", "+91", "India", R.drawable.indian_flag))
countries.add(Country("us", "+1", "United States", R.drawable.us_flag))
return countries
}