Можно ли найти возвращаемый тип метода типа параметра в Scala, где параметр является примитивным типом?

Предположим, у меня есть:

class X
{
   val listPrimitive: List[Int] = null
   val listX: List[X] = null
}

и я распечатываю возвращаемые типы каждого метода в Scala следующим образом:

classOf[ComplexType].getMethods().foreach { m => println(s"${m.getName}: ${m.getGenericReturnType()}") }

listPrimitive: scala.collection.immutable.List<Object> 
listX: scala.collection.immutable.List<X> 

Итак... Я могу определить, что типом элемента listX является X, но есть ли способ определить с помощью отражения, что тип элемента listPrimitive на самом деле является java.lang.Integer? ...

val list:List[Int] = List[Int](123);
val listErased:List[_] = list;
println(s"${listErased(0).getClass()}")  // java.lang.Integer

NB. Кажется, это не проблема из-за стирания типа JVM, поскольку я могу найти параметр типов в списке. Похоже, что компилятор scala отбрасывает эту информацию о типе, если тип параметра java.lang.[numbers] .

ОБНОВИТЬ:

Я подозреваю, что информация об этом типе доступна из-за следующего эксперимента. Предположим, я определяю:

class TestX{
  def f(x:X):Unit = {
    val floats:List[Float] = x.listPrimitive()  // type mismatch error
  }
}

и X.class импортируется через банку. Полная информация о типе должна быть доступна в X.class, чтобы в этом случае не удалось правильно скомпилировать.

ОБНОВЛЕНИЕ2:

Представьте, что вы пишете расширение scala для библиотеки сериализации Java. Вам необходимо реализовать:

def getSerializer(clz:Class[_]):Serializer

функция, которая должна делать разные вещи в зависимости от того, что:

clz==List[Int]   (or equivalently: List[java.lang.Integer])
clz==List[Float] (or equivalently: List[java.lang.Float])
clz==List[MyClass]

Моя проблема в том, что я увижу только:

clz==List[Object]
clz==List[Object]
clz==List[MyClass]

потому что clz предоставляется этой функции как clz.getMethods()(i).getGenericReturnType().

Начиная с clz:Class[_], как восстановить потерянную информацию о типе элемента?

Мне не ясно, поможет ли мне TypeToken, потому что его использование:

typeTag[T]

требует, чтобы я предоставил T (т.е. во время компиляции).

Итак, один путь к решению... Имея некоторый clz:Class[_], могу ли я определить TypeTokens возвращаемых типов его метода? Очевидно, что это возможно, поскольку эта информация должна содержаться (где-то) в файле .class, чтобы компилятор scala правильно генерировал ошибки несоответствия типов (см. выше).


person user48956    schedule 07.01.2015    source источник


Ответы (1)


На уровне байт-кода Java Int должны быть представлены как нечто другое (очевидно, Object), потому что List может содержать только объекты, а не примитивы. Вот что может вам сказать отражение на уровне Java. Но информация о типе scala, как вы понимаете, присутствует (на уровне байт-кода она находится в аннотации, IIRC), поэтому вы сможете проверить ее с помощью отражения scala:

import scala.reflect.runtime.universe._

val list:List[Int] = List[Int](123)

def printTypeOf[A: TypeTag](a: A) = println(typeOf[A])

printTypeOf(list)

Ответ на update2: для получения зеркала следует использовать отражение scala, а не объект Class[_]. Вы можете перейти через имя класса, если это необходимо:

import scala.reflect.runtime.universe._

val rm = runtimeMirror(getClass.getClassLoader)

val someClass: Class[_] = ...

val scalaMirrorOfClass = rm.staticClass(someClass.getName)
// or possibly rm.reflectClass(someClass) ?

val someObject: Any = ...

val scalaMirrorOfObject = rm.reflectClass(someObject)

Я думаю, если у вас действительно есть только класс, вы могли бы создать загрузчик классов, который загружает только этот класс? Однако я не могу представить вариант использования, в котором у вас не было бы класса или даже значения.

person lmm    schedule 07.01.2015
comment
Конечно, объекты представлены как java.lang.Integer. Но разве TypeTag не применяется только к объектам и типам. Я ищу возвращаемый тип метода (который явно известен компилятору и доступен где-то в файле класса). - person user48956; 07.01.2015
comment
Обнаружьте, что тип элемента Int (вместо java.lang.Integer) также решил бы мою проблему. Однако эта информация также отсутствует. - person user48956; 07.01.2015
comment
Я не понимаю. TypeTag — это просто помощник для получения типа; если вы проверяете возвращаемый тип метода с отражением scala, вы можете получить представление того же типа, что и от typeOf. - person lmm; 07.01.2015
comment
typeOf не помогает, потому что для этого требуется параметр типа [T], которого у меня нет. Я начинаю с класса [_], и мне нужно будет отказаться от TypeTag из возвращаемого типа метода класса. Как это может быть сделано? (Я добавил UPDATE2 выше). - person user48956; 07.01.2015
comment
mirror.classSymbol(clz).toType позволяет найти полную информацию. Спасибо! - person user48956; 08.01.2015