web-dev-qa-db-fra.com

Scala équivalent de Java java.lang.Class <T> Object

La question est mieux expliquée par un exemple:

Dans Java pour un JPA EntityManager, je peux effectuer les opérations suivantes (Account est ma classe d'entité):

Account result = manager.find(Account.class, primaryKey);

En Scala, ma tentative naïve est la suivante:

val result = manager.find(Account.class, primaryKey)

Mais quand j'essaie d'utiliser Account.class à Scala, il ne semble pas que ça se passe comme ça. Comment spécifier l'objet Java.lang.Class pour la classe Account dans Scala?

180
Kekoa

Selon " Le Scala Système de types ",

val c = new C
val clazz = c.getClass              // method from Java.lang.Object
val clazz2 = classOf[C]             // Scala method: classOf[C] ~ C.class
val methods = clazz.getMethods      // method from Java.lang.Class<T>

La méthode classOf[T] renvoie la représentation au moment de l'exécution pour un type Scala. Elle est analogue au type Java expression T.class .
Utiliser classOf[T] est pratique lorsque vous avez un type sur lequel vous souhaitez obtenir des informations, tandis que getClass permet de récupérer les mêmes informations à partir d'une instance du type.

Cependant, classOf[T] et getClass renvoient des valeurs légèrement différentes, reflétant l'effet d'effacement du type sur la machine virtuelle Java, dans le cas de getClass.

scala> classOf[C]
res0: Java.lang.Class[C] = class C

scala> c.getClass
res1: Java.lang.Class[_] = class C

C'est pourquoi le après ne fonctionnera pas :

val xClass: Class[X] = new X().getClass //it returns Class[_], nor Class[X]

val integerClass: Class[Integer] = new Integer(5).getClass //similar error

Il existe un ticket concernant le type de retour de getClass .

( James Moore indique que le ticket est "maintenant", c'est-à-dire nov. 2011, deux ans plus tard, corrigé.
En 2.9.1, getClass fait maintenant:

scala> "foo".getClass 
       res0: Java.lang.Class[_ <: Java.lang.String] = class Java.lang.String

)

De retour en 2009:

Il serait utile si Scala traitait le retour de getClass () comme un fichier Java.lang.Class [T] forSome {val T: C} où C est quelque chose comme l'effacement du type statique de l'expression sur laquelle getClass est appelée

Cela me permettrait de faire quelque chose comme ce qui suit lorsque je veux faire l'introspection d'une classe mais que je ne devrais pas avoir besoin d'une instance de classe.
Je souhaite aussi limiter les types de classes sur lesquelles je veux introspecter, aussi j’utilise Class [_ <: Foo]. Mais cela m'empêche de passer dans une classe Foo en utilisant Foo.getClass () sans casting.

Remarque: concernant getClass, une solution de contournement possible serait la suivante:

class NiceObject[T <: AnyRef](x : T) {
  def niceClass : Class[_ <: T] = x.getClass.asInstanceOf[Class[T]]
}

implicit def toNiceObject[T <: AnyRef](x : T) = new NiceObject(x)

scala> "Hello world".niceClass                                       
res11: Java.lang.Class[_ <: Java.lang.String] = class Java.lang.String
258
VonC

classOf[Account] in Scala équivaut à Account.class en Java.

48
Jonathan Graehl