Kotlin接口实现Java接口时的行为表现

3
如果我在Kotlin中有一个接口:
interface KotlinInterface {
    val id: String
}

我可以这样来实现它:
class MyClass : KotlinInterface {
    override val id: String = "id"
}

然而,如果我要使用类似这样的Java接口:
public interface JavaInterface {
    String id = "id";
}

我无法以类似的方式覆盖 id 类变量:

class MyClass : JavaInterface {
    override val myId: String = JavaInterface.id //linter says: 'myId' overrides nothing
}

尽管id有预定义的值,但我无法在其他地方使用它:

class MyClass : JavaInterface {
    val myArray: Array<String> = arrayOf(id) // linter would say that id is not defined rather than recognising it as the string “id”
}

看起来我必须这样使用它:

class MyClass {
    val id: String = JavaInterface.id
    val myArray: Array<String> = arrayOf(id)
}

能有人解释一下这个行为差异并指出我可能理解错误的部分吗?

3个回答

4
在Java接口中,每个变量都是静态的final变量,而静态变量是无法重写的。这就是为什么你会看到 lint 警告。
编辑1:
Kotlin接口
  interface Ser {
       var name: String //abstract
    }

等同于Java的接口

public interface Ser {
   @NotNull
   String getName();

   void setName(@NotNull String var1);
}

感谢回复。当两个答案出现时,我已经编辑了我的问题。如果我理解正确的话,Kotlin不允许接口属性被初始化值,而这在Java中是可能的。但是,如果我在我的Kotlin实现中不“遮盖”或“替换”那个最终的Java属性,我就无法通过名称从实现内部访问该属性(该属性在Java中已经具有一个值)。 - Cloud
当您声明一个未初始化的变量时,它被标记为抽象变量。在字节码中,Kotlin会为该变量内部创建getter和setter方法,因此您可以重写该变量。 - Jayanth
只需声明一个抽象变量的接口并查看其反编译的字节码,即可了解它的运作方式。 - Jayanth

2

我无法通过类似的方式覆盖id类变量:

在Java中也无法这样做;相当于:

class MyClass implements JavaInterface {
    @Override String getMyId() {
        return JavaInterface.id;
    }
}

getMyId 没有覆盖任何方法。

如果你用Java编写代码

class MyClass implements JavaInterface {
    String id = JavaInterface.id;
}

你并没有覆盖任何东西,因为你不能覆盖字段(此外,MyClass.id是一个非final的实例包私有字段,而JavaInterface.id隐式地是一个final静态公共字段,因为接口不允许其他类型)。

尽管它有预定义的值,但我也无法在其他地方使用id:

同样,在Java和Kotlin中都需要使用JavaInterface.id,或者使用import some.package.JavaInterface.id来使用id(在Java中使用import static)。

如果MyClass实现了JavaInterface,则存在差异,因为在Java中可以将JavaInterface.id称为MyClass.idsomeInstanceOfMyClass.id;并且在MyClass内部只能使用id。但这经常被认为是一个缺陷,所以Kotlin的设计者避免了这种情况。


你能详细说明一下关于在子类中引用实现的父接口初始化变量被称为“misfeature”的最后一部分吗?这似乎是有道理的。 - Cloud
1
请参见 https://softwareengineering.stackexchange.com/questions/49572/is-it-a-bad-practice-to-have-an-interface-to-define-constants 和 https://docs.oracle.com/javase/1.5.0/docs/guide/language/static-import.html。 - Alexey Romanov
谢谢,我发现第二个链接特别有帮助。第一个链接中的引用部分说:“对于类的用户来说,类实现常量接口并不重要。”然而,如果MyClass实现了JavaInterface,那么MyClass().id是否会对MyClass的用户可见呢? - Cloud
此外,我的问题源于这个接口的存在:https://developer.android.com/reference/android/provider/BaseColumns.html。使用它而不是“常量接口反模式”和滥用继承是否是一个好的实践呢?或者,是否更好的方法是简单地编写类似于`val id: String = JavaInterface.id`的代码? - Cloud
关于您主要答案的第二部分,我刚意识到我忘记在第五个代码片段中实现JavaInterface。我已经进行了编辑;原始编辑是在移动设备上完成的,当时错误并不明显。正如您所说的那样。然而,在Kotlin中,似乎我无法从MyClass内访问id,例如在arrayOf(id)中。 - Cloud
显示剩余3条评论

0

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接