zoukankan      html  css  js  c++  java
  • scala的反射

      如果当初Scala没有选择基于Jvm,那么Scala是否还能取得今天的成就吗?Jvm为Scala带了稳健强大的性能,同时也无法避免类型擦除的约束。
      作为Jvm上的先进语言,Scala在生成字节码时,编译器附加了额外的类型信息,及时class的泛型参数被擦除了,scala仍然可以获取泛型信息。
    主要存在三种api:

    • TypeTag,可获取一个类型的全部信息,包括高阶类型,比如List[List[List[String]]]类型。
    • ClassTag,可获取类型的部分信息。ClassTag[List[List[String]]],仅可得到类型擦除后的类的类型,也就是scala.collection.immutable.List
    • WeakTypeTag是可以用于获取抽象类型,比如def foo[A]=List.empty[A],想要获取这个抽象类型A,需要使用WeakTypeTag
    ➜ scala
    Welcome to Scala 2.12.2 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_141).
    Type in expressions for evaluation. Or try :help.
    
    scala> import scala.reflect.runtime.universe._
    import scala.reflect.runtime.universe._
    
    scala> val tt=typeTag[List[List[String]]]
    tt: reflect.runtime.universe.TypeTag[List[List[String]]] = TypeTag[scala.List[scala.List[String]]]
    
    scala> import scala.reflect._
    import scala.reflect._
    
    scala> val ct=classTag[Map[String,Int]]
    ct: scala.reflect.ClassTag[Map[String,Int]] = scala.collection.immutable.Map
    
    scala> ct.runtimeClass
    res1: Class[_] = interface scala.collection.immutable.Map
    

    利用编译器获取类型信息

      之前说过,scala编译器在编译器全部保存了相关的类型信息,仅仅需要借助隐式参数由编译器传入即可。

    import scala.reflect.runtime.universe._
    
    def typeInfo[T](x: T)(implicit tag: TypeTag[T]) = tag.tpe match {
        case TypeRef(preType: Type, symbol: Symbol, typeParams: List[Type]) =>
          println(s"preType.typeSymbol : ${preType.typeSymbol}")
          println(s"preType : ${preType}")
          println(symbol.fullName)
          println(typeParams)
      }
      
    typeInfo(Map("1"->1))
    //打印如下::
    preType.typeSymbol : package immutable
    preType : scala.collection.immutable.type
    scala.collection.immutable.Map
    List(java.lang.String, Int)
    

    在以上程序中,preType是x对象的前缀路径的类型,这里的scala.collection.immutable是一个package。symbol就是参数x的符号信息,typeParams是x对应的类型的类型参数,对于Map[String,Int],那么其类型参数有java.lang.StringInt

      一句话解释scala的反射机制:编译时期额外类型信息,此类型信息可以用编码显式给出,也可以用编译器推断。以下的例子可以说明:

    def getType[T](x: T)(implicit tag: TypeTag[T]): Type = tag.tpe
    

      现有一个函数getType(x),可以此获取某个对象x的类型信息。显式给出类型为Any,编译器则传入隐式tag:TypeTag[Any]对象。

    println(getType[Any](List(1, 2, 3)))
    //打印 Type[Any]
    println(getType(List(1, 2, 3)))
    //打印 Type[List[Int]]
    

    Type之间的比较操作

      type之间的比较主要有三种类型:

    • 比较两个类型是否是继承关系
    • 判断两个类型之间的相等性
    • 给定某一确定的类型的成员方法或者属性

      现在有两个trait,分别是AB,且AB的父级。

    trait A
    trait B extends A
    
    val aType = typeOf[A]
    val bType = typeOf[B]
    println(aType =:= bType) //false
    println(aType <:< bType) //false
    println(bType <:< aType) //true
    println(aType <:< aType) //true
    

      对于给定的两个Type实例,<:<方法可以用于比较两个类型是否具有父子类型关系,作用与Java中的isInstance类似。

      当使用==比较两个类型时,类型别名与实际类型被认为是不同类型,而=:=会用最根本的类型去比较。

    type PersonName=String
    val t1= typeOf[PersonName]
    val t2= typeOf[String]
    t1 == t2 //false
    t1 =:= t2 //true
    

      TypeTag可以等效的看作为scala2.10版本以前的ManifestClassTag也可以等效的看作为scala2.10版本之前的ClassManifest

    知难行易
    原创博文,请勿转载
    我的又一个博客hangscer.win
  • 相关阅读:
    HDU 4814
    POJ 3415
    HDU 4941
    C scanf()
    hdu 4850 Wow! Such String!
    HDU 4828 Grids
    HDU 4832 Chess
    HDU 4831
    SpringCloud 网飞系 转换阿里系2
    用jianmu建木自动化打包vue前端应用,并远程ssh建立文件夹,scp文件至对应目录
  • 原文地址:https://www.cnblogs.com/hangscer/p/8463495.html
Copyright © 2011-2022 走看看