【发布时间】:2017-12-30 19:49:09
【问题描述】:
我正在尝试使用带有返回值的访问者模式 but。
但是,虽然没有显式强制转换,但我得到了 ClassCastException:
Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.CharSequence;
at Printer.combine(...)
at Split.accept(...)
at MWEKt.main(...)
代码:
interface TreeElem {
fun <T> accept(visitor: TreeVisitor<T>): T
}
class Leaf: TreeElem {
override fun <T> accept(visitor: TreeVisitor<T>): T {
return visitor.visit(this)
}
}
class Split(val left: TreeElem, val right: TreeElem): TreeElem {
override fun <T> accept(visitor: TreeVisitor<T>): T {
return visitor.combine( // this causes cast error
visitor.visit(this),
left.accept(visitor),
right.accept(visitor))
}
}
interface TreeVisitor<T> {
// multiple implementations with different T in future (only one in this example)
fun visit(tree: Leaf): T
fun visit(tree: Split): T
fun combine(vararg inputs: T): T
}
class Printer: TreeVisitor<CharSequence> {
override fun combine(vararg inputs: CharSequence): CharSequence { // error here
return inputs.joinToString(" ")
}
override fun visit(tree: Leaf): CharSequence { return "leaf" }
override fun visit(tree: Split): CharSequence { return "split" }
}
fun main(args: Array<String>) {
val tree = Split(Leaf(), Leaf())
val printer = Printer()
println(tree.accept(printer))
}
我不知道问题是什么。我是在尝试做一些不可能的事情,还是我没有正确表达它,或者是类型擦除使本来应该可能的事情变得不可能?
到目前为止我的想法:
-
Printer.combine预计CharSequences; - 我正在调用
TreeElem.accept的泛型重载,它返回CharSequence - 编译器可能会在 JVM 代码中插入强制转换(类型擦除?)
- 但是运行时类型是兼容的,所以转换应该可以工作
由于最后一点与现实主义相冲突,我可能理解错误。
编辑:我已将 MWE 翻译成 Java 以查看它是否是 Kotlin 问题并吸引答案:
interface TreeElem {
<T> T accept(TreeVisitor<T> visitor);
}
class Leaf implements TreeElem {
public <T> T accept(TreeVisitor<T> visitor) {
return visitor.visit(this);
}
}
class Split implements TreeElem {
private TreeElem left;
private TreeElem right;
Split(TreeElem left, TreeElem right) {
this.left = left;
this.right = right;
}
public <T> T accept(TreeVisitor<T> visitor) {
return visitor.combine(
visitor.visit(this),
left.accept(visitor),
right.accept(visitor));
}
}
interface TreeVisitor<T> {
T visit(Leaf tree);
T visit(Split tree);
T combine(T... inputs);
}
class Printer implements TreeVisitor<CharSequence> {
public CharSequence combine(CharSequence... inputs) {
StringBuilder text = new StringBuilder();
for (CharSequence input : inputs) {
text.append(input);
}
return text;
}
public CharSequence visit(Leaf tree) { return "leaf"; }
public CharSequence visit(Split tree) { return "split"; }
}
public class MWEjava {
public static void main(String[] args) {
TreeElem tree = new Split(new Leaf(), new Leaf());
Printer printer = new Printer();
System.out.println(tree.accept(printer));
}
}
Java 案例的错误是一样的。
【问题讨论】:
标签: java generics kotlin type-erasure visitor-pattern