Как преодолеть ошибку "такой же JVM-подписи" при реализации интерфейса Java?

С приведенным ниже кодом я получаю следующую ошибку в IntelliJ IDEA 13.1.6 и плагине Kotlin 0.11.91.AndroidStudio.3:

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
}

Но в моем реальном случае у меня есть ряд свойств для реализации и нуждающихся в настройках. Делать это для каждого свойства не кажется очень Kotlin-ish. Что мне не хватает?

Ответ 1

Создание этой переменной private решает проблему.

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

Ответ 2

Еще одна задача - объявить свойства абстрактного класса Kotlin, а затем написать небольшой класс java, который расширяет KotlinClass и реализует JavaInterface.

// 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.
}

Ответ 3

Вы можете использовать @JvmField для указания компилятору не генерировать getter/setter, и вы можете реализовать свои сеттеры и геттеры. Благодаря этому ваш код хорошо работает на Java (в качестве атрибута getter/setter) и Kotlin as property

Пример: JAVA

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

Котлин

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

Ответ 4

Если у вас есть прямой контроль над интерфейсом, лучший подход - написать интерфейс в Kotlin. Затем вы можете написать свой класс

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

и по-прежнему ссылаться на него с любого Java-кода, используя тот же интерфейс, что и раньше. Это выглядит намного опрятно, чем установка всех свойств в частные и переопределение функции get. Очевидно, что если вы не можете перенести интерфейс на Java, потому что вы его не владеете, это единственное решение.

Ответ 5

Мы обнаружили, что для использования одинаковых имен без столкновения ctor args должен быть private. И вы должны по-прежнему переопределять методы интерфейсов. Вам не нужны дополнительные поля поддержки. Кроме того, назначение тела выражения не будет возвращаться, поэтому вы можете безопасно использовать этот синтаксис.

Интерфейс 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
}

Ответ 6

ИМХО наиболее читаемым сочетанием является реализация поля + явного интерфейса с помощью функции с одним выражением (комбинация ответов @Renato Garcia и @Steven Spungin):

Джава:

public inteface SomeInterface {
    String getFoo();
}

Котлин:

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

Ответ 7

public interface JavaInterface {
    public String getName();
}

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

private var name = namePrivate

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

Ответ 8

Переименуйте переменную в другое или сделайте ее закрытой, если вы не хотите, чтобы она была публичной.

Ответ 9

мы можем это сделать!

package com.example.mykotlin

import android.support.v7.app.AppCompatActivity
import android.os.Bundle
import kotlinx.android.synthetic.main.activity_main.*

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        tv.text = "Hello MyKotlin"
        tv.textSize = 20.0f
    }
}