我正在尝试使用Kotlin扩展第三方Java类,但是我得到了这个编译器消息:
继承的平台声明冲突:以下声明具有 相同的JVM签名(setCollection(Ljava / util / Collection;)V):
fun setCollection(collection:(Mutable)Collection<(raw)Any?>!:KotlinClass中定义的单位
fun setCollection(collection:(Mutable)Collection< String!>!):在KotlinClass中定义的单位
无论我做什么,都无法用Kotlin代码编译它。
重现情况的代码:
//JavaInterface.class
import java.util.Collection;
public interface JavaInterface {
void setCollection(Collection<String> collection);
}
//JavaBaseClass.class
import java.util.Collection;
public class JavaBaseClass {
public void setCollection(Collection collection){}
}
//JavaSubClass.class
public class JavaSubClass extends JavaBaseClass implements JavaInterface {}
//KotlinClass.kt
class KotlinClass : JavaSubClass()
Java本身没有这个问题。所以我猜这可能与平台类型有关(String!
不是Any?
)。
这个问题有一个优雅的解决方法,最好不要编写Java代码吗?或者这应该在Kotlin编译器本身内修复?
答案 0 :(得分:0)
我没有仔细研究java如何/为什么在JavaSubClass中工作的细节,即它产生的字节码,但从Kotlin的角度来看,如果我看一下这两种方法的签名,它们会有不明确的调度。
此:
public void setCollection(Collection collection){}
被视为设置具有泛型类型Any的Collection的方法。 任何?是String的超集。
如果您班级的客户有以下内容:
myCollection = Array<String>()
myInstanceOfKotlinClass.setCollection(myCollection)
应该调派哪种方法?
出于这个原因,我认为这不是Kotlin编译器中的错误,而是对一些更宽松的java泛型类型安全性的改进。显然,java可以选择这两个方法如何在字节码中编译到同一个类中,如果您知道在上述情况下将选择哪个方法进行调度,那么这是一个好的方法。但我认为你应该能够单独从签名中分辨哪一个,而不是一些内部知识。
我担心我正在努力找到一种解决方法,它会为你提供一个类型的扩展kotlin类。因此,如果您想要为该java类添加更多功能,并且您不需要任何额外的实例状态,您可以尝试使用扩展函数吗?
fun JavaSubClass.newFunctionality(){}
感觉就像你使用的第三方代码本身在使用泛型和继承方面做得很差。无论哪种方式,如果您需要更改现有功能的行为或具有新功能的实例状态,我认为您在Java土地中处理这种歧义时会陷入困境,因为Kotlin不同意这一点我认为是原则问题。
编辑:
看看java,这个
//JavaSubClass.class
public class JavaSubClass extends JavaBaseClass implements JavaInterface {}
意味着JavaBaseClass实现了接口....
它扩展了接口的泛型类型。令人讨厌的类型擦除即将到来。我的意思是看看这个:
import java.util.ArrayList;
public class Main {
public static void main(String[] args) {
JavaSubClass sc = new JavaSubClass();
ArrayList<Integer> myCollection = new ArrayList<>();
sc.setCollection(myCollection);
}
}
Eeew。