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删除,使得某些事情变得不可能?

我的想法到目前为止:

  1. Printer.combine期望CharSequence s;
  2. 我正在调用返回CharSequenceTreeElem.accept的generics重载
  3. 编译器可能会在JVM代码中插入一个强制转换(type erasure?)
  4. 但运行时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很好。