【问题标题】:Inheritance from Java class with a public method accepting a protected class in Kotlin使用接受 Kotlin 中受保护类的公共方法从 Java 类继承
【发布时间】:2018-08-23 08:34:47
【问题描述】:

我有这种情况: 有一个Java类

public class A {

    public void overrideMe(B param){
        //TODO: override me in Kotlin!
    }

    protected static class B {

    }
}

还有一个 Kotlin 类,它继承自它并且必须覆盖方法“overrideMe”

class K: A() {
    override fun overrideMe(param: B) {
        println("Wow!")
    }
}

但 Kotlin 不允许这种行为。

'public' 函数暴露了它的 'protected (in A)' 参数类型 B

有什么办法可以解决这个问题吗?

附:这不仅仅是一个综合案例 - 当我尝试实现自定义 Spring AmqpAppender 并覆盖它的 postProcessMessageBeforeSend 方法时,我遇到了这个问题。

【问题讨论】:

  • 在 Java 中可以实现这一点让我感到非常惊讶。
  • B 被保护并且函数是公共的,错误是有道理的,不知道为什么Java 没有提前警告。
  • 我认为这是我们生活在模拟中的权威证明
  • 我认为您应该使用 internal 关键字,正如我在回答中所述。这使您可以在模块中使用 B,但不能从外部访问它。
  • @leoderprofi 不幸的是,在我的例子中,有一个适当的 Spring AmqpAppender 类,用 java 编写。所以我没有“使用内部”选项

标签: java inheritance kotlin protected kotlin-interop


【解决方案1】:

在 Kotlin 中无法解决此问题,原因如下:

不同之处在于 protected 实际上在 Kotlin 中的含义与在 Java 中的含义略有不同。

protected in Kotlin 表示:

kotlin protected: 与 private 相同(在包含声明的文件中可见)+ 在子类中也可见;

Java 中的protected 表示:

java protected:该成员只能在其自己的包中访问(与 package-private 一样),此外,它的类在另一个包中的子类也可以访问。

有了这些知识,问题应该很清楚了,Kotlin 中的 protected static class B 更像 Java 中的 private static class B。因此警告是正确的。

Kotlin-Java Interop 指南特别指出:

protected 仍然是 protected(请注意,Java 允许从同一个包中的其他类访问受保护的成员,而 Kotlin 不允许,因此 Java 类将拥有更广泛的代码访问权限);

结论:

这意味着 Kotlin 将 Java-protected 解释为好像它是 Kotlin-protected 那样,因此无法在 Kotlin 中实现 class K。要使其正常工作,您至少必须创建 C extends A(在 Java 中)来处理 B 的所有公共访问,然后在 Kotlin 中扩展此类。就像在这个问题上Calling protected static methods

罪魁祸首:

主要问题是static nested classes的Java行为,

与其外部类(和其他类)的实例成员交互,就像任何其他顶级类一样。 实际上,静态嵌套类在行为上是一个顶级类,为了方便打包,它已经嵌套在另一个顶级类中

这种方便的行为首先会造成问题。

旁注:

可能更适合 Java-protected 的是 Kotlins internal,它提供了更好的封装级别。

kotlin internal:该模块内任何看到声明类的客户端都会看到它的内部成员;

【讨论】:

  • 但是问题中没有“protected static class B in Kotlin”:它继承自Java A类。
  • 我明白了,很遗憾,我认为无法在 Kotlin 中扩展 A,请参阅我的更新
  • 这对我来说似乎相当虚假;使用 Java,子类可以毫无问题地引用超类中的受保护静态内部类(例如,在被覆盖的方法参数中)。当然,Kotlin 也应该这样做,以便 Kotlin 用户可以与现有的 Java 库进行互操作,而无需强制这些库“仅仅”为了 Kotlin 兼容性而进行更改。
  • 也许这会改变,但看看线程(例如discuss.kotlinlang.org/t/…),他们似乎很喜欢他们的意见。也许他们会在以后的版本中针对这个特定案例引入一些东西。
  • @leoderprofi 我昨天与Roman Elizarov 进行了简短的交谈。结论是:“没办法”。
【解决方案2】:

好吧,毕竟结论是:纯Kotlin没有办法解决这种情况。

我希望 AmqpAppender.Event 能在不久的将来公开。

即使 Java 允许这种行为,在公共方法中使用非公共参数对我来说似乎是一个糟糕的设计(对于 Kotlin 的开发人员也是如此)。

【讨论】:

    猜你喜欢
    • 2012-08-19
    • 1970-01-01
    • 2016-01-01
    • 2015-05-16
    • 2010-09-14
    • 1970-01-01
    • 1970-01-01
    • 2020-09-09
    • 1970-01-01
    相关资源
    最近更新 更多