отражение scala, тип приведения с помощью asInstanceOf

#scala #reflection #types #casting

#scala #отражение #типы #Кастинг

Вопрос:

У меня есть

 trait T
class C extends T
  

компилируется в файлы .class. Запустите scala с -cp <...> , чтобы иметь T доступный тип. Затем загрузите класс C, используя отражение:

 val loader = ScalaClassLoader fromURLs (/* List[URL] */)
val anyC = loader.tryToInitializeClass("C") getOrElse (/* throw something */)
val classC = anyC.asInstanceOf[Class[T]]
  

Как я могу привести classC.newInstance к типу T , например

 val objC = classC.newInstance.asInstanceOf[T] 
// yields java.lang.ClassCastException: C cannot be cast to T
  

Ответ №1:

Вы должны загружать класс C из другого загрузчика классов, отличного от T загружаемого.

Вы поместили оба T и C в путь к классу REPLs, поэтому одним из вариантов может быть загрузка C через системный загрузчик классов. Пример сеанса REPL,

 scala> val loader = scala.tools.nsc.util.ScalaClassLoader.getSystemLoader
loader: scala.tools.nsc.util.ScalaClassLoader =
  scala.tools.nsc.util.ScalaClassLoader$$anon$1@985d2e0

scala> val anyC = loader.tryToInitializeClass("C") getOrElse (sys.error("Boom"))
anyC: Class[Nothing] = class C

scala> val classC = anyC.asInstanceOf[Class[T]]
classC: Class[T] = class C
  

Примечание. на самом деле это уже не вопрос, специфичный для Scala.

Комментарии:

1. Итак, есть ли какой-нибудь способ «объединить» эти два загрузчика классов?

2. Это действительно зависит от того, что вы пытаетесь сделать. Я отредактировал ответ, чтобы показать один вариант.

3. Да, я хочу проверить, реализовал ли пользователь trait предоставленное. Я нашел способ val loader = ScalaClassLoader fromURLs (/* List[URL] */, classOf[T].getClassLoader) , вот и все. Спасибо за вашу помощь!