Java / Kotlin使用generics返回types为访问者模式强制转换exception
我试图使用类似访问者模式, 但与返回值。
但是,虽然没有明确的转换,但我得到一个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 accept(visitor: TreeVisitor): T } class Leaf: TreeElem { override fun accept(visitor: TreeVisitor): T { return visitor.visit(this) } } class Split(val left: TreeElem, val right: TreeElem): TreeElem { override fun accept(visitor: TreeVisitor): T { return visitor.combine( // this causes cast error visitor.visit(this), left.accept(visitor), right.accept(visitor)) } } interface TreeVisitor { // 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 { 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) { val tree = Split(Leaf(), Leaf()) val printer = Printer() println(tree.accept(printer)) }
我不知道是什么问题。 我是想做一件不可能的事情,还是我没有正确地expression出来,或者是在进行types删除,使得某些事情变得不可能?
我的想法到目前为止:
-
Printer.combine
期望CharSequence
s; - 我正在调用返回
CharSequence
的TreeElem.accept
的generics重载 - 编译器可能会在JVM代码中插入一个强制转换(type erasure?)
- 但运行时types是兼容的,所以投射应该工作
由于最后一点是与现实主义冲突,我可能不正确地理解一些东西。
编辑:我已经翻译了MWE到Java,看看这是否是一个Kotlin问题,并吸引一个答案:
interface TreeElem { T accept(TreeVisitor visitor); } class Leaf implements TreeElem { public T accept(TreeVisitor 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 accept(TreeVisitor visitor) { return visitor.combine( visitor.visit(this), left.accept(visitor), right.accept(visitor)); } } interface TreeVisitor { T visit(Leaf tree); T visit(Split tree); T combine(T... inputs); } class Printer implements TreeVisitor { 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情况,错误是一样的。
我很确定这是这个问题的重复: https : //stackoverflow.com/a/9058259/4465208
然而,要提供一个特定的解决方案,你可以用一个List
来代替vararg
参数,这样可以很好地工作:
class Split(val left: TreeElem, val right: TreeElem) : TreeElem { override fun accept(visitor: TreeVisitor ): T { return visitor.combine(listOf( visitor.visit(this), left.accept(visitor), right.accept(visitor))) } } interface TreeVisitor { fun combine(inputs: List ): T // ... } class Printer : TreeVisitor { override fun combine(inputs: List ): CharSequence { return inputs.joinToString(" ") } // ... }
不是很漂亮,但它与generics很好。