当isInstanceOf在带有通配符参数的scala类型上返回true时,为什么会出现ClassCastException?

时间:2013-08-13 07:51:40

标签: scala reflection classcastexception

我的问题是:

  1. 这个警告是什么? reflect.runtime.universe.TypeRef
  2. 没有类型参数
  3. 为什么会抛出方法调用 arg 而不是 asInstanceOf
  4. 控制台输出:

    Welcome to Scala version 2.10.0 (Java HotSpot(TM) Client VM, Java 1.6.0_35).
    Type in expressions to have them evaluated.
    Type :help for more information.
    
    scala>  import reflect.runtime.{universe => ru}
    import reflect.runtime.{universe=>ru}
    
    scala>  val t = ru.typeOf[Option[_]]
    t: reflect.runtime.universe.Type = scala.Option[_]
    
    scala>  t.isInstanceOf[ru.TypeRef]
    <console>:10: warning: abstract type reflect.runtime.universe.TypeRef is unchecked since it is eliminated by erasure
                  t.isInstanceOf[ru.TypeRef]
                                ^
    res0: Boolean = true
    
    scala>  t.asInstanceOf[ru.TypeRef]
    res1: reflect.runtime.universe.TypeRef = scala.Option[_]
    
    scala>  t.asInstanceOf[ru.TypeRef].args
    java.lang.ClassCastException: scala.reflect.internal.Types$ExistentialType cannot be cast to scala.reflect.api.Types$TypeRefApi
        at .<init>(<console>:10)
        at .<clinit>(<console>)
        at .<init>(<console>:7)
        at .<clinit>(<console>)
        at $print(<console>)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at scala.tools.nsc.interpreter.IMain$ReadEvalPrint.call(IMain.scala:731)
        at scala.tools.nsc.interpreter.IMain$Request.loadAndRun(IMain.scala:980)
        at scala.tools.nsc.interpreter.IMain.loadAndRunReq$1(IMain.scala:570)
        at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:601)
        at scala.tools.nsc.interpreter.IMain.interpret(IMain.scala:565)
        at scala.tools.nsc.interpreter.ILoop.reallyInterpret$1(ILoop.scala:745)
        at scala.tools.nsc.interpreter.ILoop.interpretStartingWith(ILoop.scala:790)
        at scala.tools.nsc.interpreter.ILoop.command(ILoop.scala:702)
        at scala.tools.nsc.interpreter.ILoop.processLine$1(ILoop.scala:566)
        at scala.tools.nsc.interpreter.ILoop.innerLoop$1(ILoop.scala:573)
        at scala.tools.nsc.interpreter.ILoop.loop(ILoop.scala:576)
        at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply$mcZ$sp(ILoop.scala:867)
        at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:822)
        at scala.tools.nsc.interpreter.ILoop$$anonfun$process$1.apply(ILoop.scala:822)
        at scala.tools.nsc.util.ScalaClassLoader$.savingContextLoader(ScalaClassLoader.scala:135)
        at scala.tools.nsc.interpreter.ILoop.process(ILoop.scala:822)
        at scala.tools.nsc.interpreter.ILoop.main(ILoop.scala:889)
        at org.jetbrains.plugins.scala.compiler.rt.ConsoleRunner.main(ConsoleRunner.java:64)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.intellij.rt.execution.application.AppMain.main(AppMain.java:120)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at com.intellij.rt.execution.CommandLineWrapper.main(CommandLineWrapper.java:121)
    

1 个答案:

答案 0 :(得分:3)

TypeRef是一个抽象类型,因此它被删除到它的上限。通常这意味着不可能进行可靠的isInstanceOf和模式匹配(最终依赖于此)。

然而,由于反射API广泛使用抽象类型,我们内置了一种特殊的机制来基于类标记模式匹配抽象类型的实例。如果在范围内,您有一个对应于抽象类型的类标记,则一切都可靠地工作。

当然,我们提供了一组捆绑在Universe中的类标记,几乎每种抽象类型都有一个。问题是您需要导入这些类标记。通常这不是一个问题,因为几乎所有人都import ru._,但在这样的情况下它会出现。我们认为这是一个问题,但仍有待解决。