scalaのクラスとタイプ

7639 ワード

scalaのクラスとタイプ
クラスとタイプ
ListとListのタイプは異なりますが、jvmの実行時には汎用消去が使用されます.これにより、ListとListの両方がClassとなる.正しいタイプを得るためには、反射が必要です.
汎用消去
Javaの汎用型は基本的にコンパイラという階層で実現されています.生成されたJavaバイトコードには、汎用的なタイプ情報は含まれません.汎用型を使用するときに付けたタイプパラメータは、コンパイラがコンパイルするときに削除されます.このプロセスをタイプ消去と呼びます.汎用消去はjdk 1と互換性があるためである.5以前のjvmは、それ以前は汎用型をサポートしていませんでした.
classOfとgetClassメソッドの違い
scala> class A
scala> val a = new A

scala> a.getClass
res2: Class[_ <: A] = class A

scala> classOf[A]
res3: Class[A] = class A

両者の違いを示しているが,getClassメソッドで得られるのはClass[A]のあるサブクラスであり,classOf[A]で得られるのは正しいClass[A]であるが,比較すると,この2つのタイプはequalsがtrueである.
classOfとgetClass
classOfは、実行時のタイプを取得します.classOf[T]はjavaのT.classに相当する
   val listClass = classOf[List[_]]
   * // listClass is java.lang.Class[List[_]] = class scala.collection.immutable.List
   val mapIntString = classOf[Map[Int,String]]
   * // mapIntString is java.lang.Class[Map[Int,String]] = interface scala.collection.immutable.Map
   * }}}

getClass:
scala> class A
scala> val a = new A

scala> a.getClass
res2: Class[_ <: A] = class A

scala> classOf[A]
res3: Class[A] = class A

両者の違いを示しているが,getClassメソッドで得られるのはClass[A]のあるサブクラスであり,classOf[A]で得られるのは正しいClass[A]であるが,比較すると,この2つのタイプはequalsがtrueである.
scala> a.getClass  == classOf[A]
res13: Boolean = true

このような微細な違いは,タイプ付与時に現れるが,javaのClass[T]はコヒーレントをサポートしないため,1つのClass[<:A]を1つのClass[A]に付与することはできない.
scala> val c:Class[A] = a.getClass
<console>:9: error: type mismatch;
(class) (type) (javaでは初期からclassでtypeを表現していたため、現在もこのような習慣が続いている).タイプ(type)はクラス(class)よりも「具体的」で、どのデータにもタイプがあります.クラスはオブジェクト向けシステムにおける同じクラスのデータに対する抽象であり,汎用がない前にタイプシステムには高次概念は存在せず,直接クラスと1つずつマッピングされ,汎用が現れた後,1つずつマッピングされなくなった.例えばclass List[T]{}を定義すると、List[Int]やList[String]などの具体的なタイプがあり、それらのクラスは同じListであるが、タイプは異なる構造パラメータタイプによって異なる.
タイプが一致するオブジェクトは、クラスも一致します.逆に、クラスが一致し、そのタイプが一致するとは限りません.
scala> classOf[List[Int]] == classOf[List[String]]
res16: Boolean = true

scala> typeOf[List[Int]] == typeOf[List[String]]
res17: Boolean = false

ClassTag
ClassTag[T]は、汎用消去された元のタイプTを保存し、実行時に提供する.
scala> def mkArray[T : ClassTag](elems: T*) = Array[T](elems: _*)
mkArray: [T](elems: T*)(implicit evidence$1: scala.reflect.ClassTag[T])Array[T]

TypeTag
TypeTagはすべての特定のタイプを保存します
import scala.reflect.runtime.universe._
def paramInfo[T](x: T)(implicit tag: TypeTag[T]): Unit = {
  val targs = tag.tpe match { case TypeRef(_, _, args) => args }
  println(s"type of $x has type arguments $targs")
}
scala> paramInfo(42)
type of 42 has type arguments List()
scala> paramInfo(List(1, 2))
type of List(1, 2) has type arguments List(Int)

取得されたタイプは、消去されたタイプList(Any)ではなく、特定のタイプであることがわかる
Reference
http://hongjiang.info/scala-type-system-classof-and-getclass/http://hongjiang.info/scala-type-and-class/http://www.scala-lang.org/files/archive/nightly/docs/library/index.html#scala.reflect.ClassTag http://blog.csdn.net/lonelyroamer/article/details/7868820