2017-12-30 34 views
1

방문자 패턴과 같은 것을 사용하려고합니다. 반환 값은 but입니다.일반적인 반환 유형의 방문자 패턴에 대한 Java/Kotlin 캐스트 예외

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)) 
} 

나는 문제가 무엇인지 모르는 명시 적 캐스트가 없지만 그러나

는, 나는 ClassCastException를 얻고있다. 불가능한 일을하려고합니까, 아니면 정확하게 표현하지 못하거나 불가 능할 수있는 것을 만들어내는 형식을 지우고 있습니까?

내 생각이 지금까지 :

  1. Printer.combineCharSequence의 기대;
  2. 나는 CharSequence
  3. 이 컴파일러는 아마도 JVM 코드에 깁스를 삽입 반환 TreeElem.accept의 일반적인 과부하 전화 드렸습니다 (유형 삭제를?)
  4. 그러나 캐스트가
  5. 를 작동해야하므로 런타임 유형은 호환

마지막 점이 현실 주의자와 충돌하기 때문에 나는 아마도 잘못 이해하고있을 것입니다.

편집 : 나는 그것이 코 틀린 문제인지 확인하고 답변을 유치하기 위해 자바에 MWE을 번역했습니다

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)); 
    } 
} 

오류가 자바의 경우에 대해 동일합니다.

답변

1

내가이이 질문의 중복 확신 :

그러나 https://stackoverflow.com/a/9058259/4465208

, 특정 솔루션을 제공하기 위해, 당신은 잘 작동합니다 대신 List<T>vararg 인수를 대체 할 수

class Split(val left: TreeElem, val right: TreeElem) : TreeElem { 
    override fun <T> accept(visitor: TreeVisitor<T>): T { 
     return visitor.combine(listOf(
       visitor.visit(this), 
       left.accept(visitor), 
       right.accept(visitor))) 
    } 
} 

interface TreeVisitor<T> { 
    fun combine(inputs: List<T>): T 
    // ... 
} 

class Printer : TreeVisitor<CharSequence> { 
    override fun combine(inputs: List<CharSequence>): CharSequence { 
     return inputs.joinToString(" ") 
    } 
    // ... 
} 

귀엽지 만, 제네릭과 잘 어울립니다.

+1

감사합니다. 어쨌든 나는''L '을 인식하지 못했습니다. 배열 때문에 배열이 실패했음을 깨달았을 수도 있습니다 ... – Mark

+0

놓치기 쉬운 일 이죠. 항상 저에게 일어납니다. :) – zsmb13