【发布时间】:2018-04-16 15:08:31
【问题描述】:
我在尝试将带有嵌套泛型的 Java 代码转换为 Kotlin 时遇到了一些麻烦。以这个 Java SSCCE 为例(请注意 S 和 T 的关系):
public class JavaTest {
private class JavaObjectContainer<S> {
public S obj;
}
private abstract class JavaSampleClass<S, T extends JavaObjectContainer<S>> {
private Class<S> type;
public JavaSampleClass(Class<S> type) {
this.type = type;
}
public Class<S> getType() {
return type;
}
public abstract void callMethod(S s);
}
private class JavaChildSampleClass extends JavaSampleClass<String, JavaObjectContainer<String>> {
public JavaChildSampleClass() {
super(String.class);
}
@Override
public void callMethod(String s) {}
}
private class JavaTestContainer {
private Map<Class<?>, JavaSampleClass> sampleClasses;
public JavaTestContainer() {
this.sampleClasses = new HashMap<>();
}
public void registerJavaSampleClass(JavaSampleClass javaSampleClass) {
sampleClasses.put(javaSampleClass.getType(), javaSampleClass);
}
public void callMethod(Object obj) {
sampleClasses.get(obj.getClass()).callMethod(obj);
}
}
public void test() {
JavaTestContainer javaTestContainer = new JavaTestContainer();
javaTestContainer.registerJavaSampleClass(new JavaChildSampleClass());
javaTestContainer.callMethod("Hola");
}
}
将此 SSCCE 视为通用工厂模式的实现,其中用户注册多个 JavaSampleClass,其方法可以在将来调用。
由于 Kotlin 没有提供通配符的替代方案,我尝试了以下方法:
class KotlinTest {
private class KotlinObjectContainer<S> {
var obj : S? = null
}
private open class KotlinSampleClass<S, T : KotlinObjectContainer<S>>(var type: Class<S>) {
fun callMethod(s : S) {}
}
private class KotlinChildSampleClass : KotlinSampleClass<String, KotlinObjectContainer<String>>(String::class.java)
private inner class KotlinTestContainer {
private val sampleClasses: MutableMap<Class<Any>, KotlinSampleClass<Any, KotlinObjectContainer<Any>>> = mutableMapOf()
fun registerKotlinSampleClass(kotlinSampleClass: KotlinSampleClass<Any, KotlinObjectContainer<Any>>) {
sampleClasses.put(kotlinSampleClass.type, kotlinSampleClass)
}
fun callMethod(obj : Any) {
sampleClasses[obj.javaClass]?.callMethod(obj)
}
}
fun test() {
val kotlinTestContainer = KotlinTestContainer()
// Exception!
kotlinTestContainer.registerKotlinSampleClass(KotlinChildSampleClass())
kotlinTestContainer.callMethod("Hello")
}
}
以上代码在IDE中抛出如下异常:
Type mismatch.
Required: KotlinTest.KotlinSampleClass<Any, KotlinObjectContainer<Any>>
Found: KotlinTest.KotlinChildSampleClass
我一直在考虑将 sampleClasses 映射声明为
MutableMap<*, *>
但是,我该如何初始化它呢?此外,由于 * 表示投影参数,因此 IDE 在尝试将新值放入地图时会向我显示错误。
我该如何克服这个问题?我很确定我错过了什么......
【问题讨论】:
-
可能不相关,但仍然有代码味道:Don't use raw types.
-
如果我没记错的话,使用原始类型基本上是使这种方法在 Java 中如此强大的原因。我已经为多类型 RecyclerView.Adapter 实现了一些类似的东西。这只是一个谨慎的问题,并添加一层保护以确保您尝试访问已添加的工厂。无论如何,我会研究你的观察,谢谢!
标签: java android generics kotlin