问题描述
在下面,由于 T
是具体化的,我想通过访问它的伴随对象来使用它 "almost as if it were a normal class"。
class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T> func() {
T.method() // error
}
fun main() {
func<Cls>()
}
但是失败了
Type parameter 'T' cannot have or inherit a companion object,so it cannot be on the left hand side of dot
因此似乎丢失了大量信息。使用和不使用 reified
时我都会遇到相同的错误。我希望 reified
类型参数比 Java 的实现更全面。我在 C++ 模板方面拥有丰富的经验。
我找到了一些解决方法(使用反射都非常令人失望),但我真的在问为什么这行不通。
解决方法
我不确定这是否回答了所有问题,但评论太大了。
首先,正如评论中所述,代码的编写方式,T
不一定是 Cls
,因此您需要进行一些更改:
open class Cls {
companion object {
fun method() { }
}
}
inline fun <reified T : Cls> func() {
}
打开课程,让 Kotlin 知道 T
是一个 Cls
然而,即使它是内联的,这仍然不会让您调用伴随方法,因为 T
没有伴随方法。即使没有泛型:
open class Cls {
companion object {
fun method() { }
}
}
class Foo : Cls
fun main() = Foo.method() // doesn't work
不起作用,因为同伴不是继承的。为什么?这是 Kotlin 设计师有意识的决定。如您所知,Kotlin 旨在纠正 Java 存在的许多问题,这就是其中之一。
Java 中的静态方法是在编译时绑定的,而覆盖是基于运行时的动态绑定。当您将两者混合使用时,这会变得非常混乱,而 Kotlin 试图避免这种情况。举个例子:
class Cls {
public static void method() {
System.out.println("Cls' method");
}
}
class Foo extends Cls {
public static void method() {
System.out.println("Foo's method");
}
}
public class Main {
public static void main(String[] args) {
Cls parent = new Foo();
parent.method();
}
}
如果 method
真的被覆盖,它会打印出 Foo's method
,但确实会打印出 Cls' method
。原因是没有覆盖,但有阴影发生。另一方面,如果方法不是静态的,那么您会得到 Foo's method
,因为它确实被覆盖了。这显然引起了开发人员的混淆,Kotlin 完全不允许这样做。