(Scala 16) 高级类型和反射

/**
  * 第16章 高级类型
  */

//########################### 16.1 类型与类的区别 #################################
import com.shuai.module_16._

import scala.collection.mutable
import scala.reflect.runtime.universe._

//class A {}

typeOf[A] //reflect.runtime.universe.Type = com.shuai.module_16.A
classOf[A] //Class[com.shuai.module_16.A] = class com.shuai.module_16.A

val a = new A
a.getClass //Class[T] = class com.shuai.module_16.A


//trait T {}

typeOf[T] //reflect.runtime.universe.Type = com.shuai.module_16.T
classOf[T] //Class[com.shuai.module_16.T] = interface com.shuai.module_16.T
val t = new T {}
t.getClass

//object O {}
//classOf[O] //这里O是一个单例对象
//对于实例,要获取它的Class信息,只有通过getClass方法
O.getClass // Class[T] = class com.shuai.module_16.O$
//注意到了,上面的单例对象O对应的class是O$而不是O,你通过:javap O也能看到这个单例反编译后是一个名为O$的java class

//嵌套类
val a1 = new A
val a2 = new A
val b1 = new a1.B
val b2 = new a2.B

b1.getClass
b2.getClass
b1.getClass == b2.getClass
b1 == b2 //Scala内部类是属于实例对象的,Java内部类是属于类的

typeOf[A]
typeOf[a2.B]
typeOf[A#B]


//########################### 16.2 classOf与getClass的区别 #################################

class C

val c = new C

c.getClass // class com.shuai.module_16.A$A12$A$A12$C


classOf[A] //class com.shuai.module_16.A

/**
  * getClass得到的是Class[A]的某个子类
  * classOf[A]得到的是正确的Class[A],但是比较的话equals = true
  */
c.getClass == classOf[C]


/**
  * 这种细微的差别,体现在类型赋值时,因为java里的Class[T]是不支持协变的,所以无法把
  * 一个Class[_<:A]赋值给一个Class[A]
  */
val c2 = c.getClass


val c3: Class[A] = classOf[A]


//########################### 16.3 单例类 #################################
object D {
  def ddd = {
    println("ddddd.....")
  }
}


D.getClass //class com.shuai.module_16.A$A13$A$A13$D$
typeOf[D.type] //A$A13.this.D.type


//对于这种单例,它的类型与它的类不同,要用A.type来表示,这有点奇怪,通常我们不会用它,比如下面的方式都是多此一举:

val d1: D.type = D
def foo(): D.type = D
d1.ddd

val d3: D.type = D
d1 == d3 //true
d1.getClass == d3.getClass //true


/**
  * 一方面是因为scala有类型推导功能,另一方面,因为单例是唯一的,A.type类型只有唯一一个实例A(拍出null),
  * 我们需要用的话直接用A就好了
  */
D.ddd

/**
  * 如果A是一个对象实例,是否对实例x都存在一个x.type这样的类型呢?
  */

class E

val e1 = new E //com.shuai.module_16.A$A19$A$A19$E@5664cdf4
typeOf[e1.type] //A$A19.this.e1.type

//看来实例是存在对应的e1.type这样类型的,再用这个类型声明一个变量看看:
val x: e1.type = e1 //com.shuai.module_16.A$A20$A$A20$E@3a389bb3

///再用这个类型去赋值一个非e1的实例呢?
val e2 = new E
//val x2: e1.type = e2 //type mismatch

typeOf[e1.type] == typeOf[E] //false, e1.type与E不是同一个类型

typeOf[e1.type] == typeOf[e2.type] //false, e1.type与e2.type也不是同一个类型

typeOf[E]
typeOf[e1.type]
typeOf[e1.type] <:< typeOf[E] //true , e1.type是E类型的子类型
/**
  * 看到了,e1.type与e2.type是不同的类型! e1.type也是单例类型,它也只有唯一的实例:a(排除null)
  */

/**
  * 所有的对象实例都有一个x.type的单例类型,它只对应当前对象实例
  * 这么做有什么意义呢?
  * 单例类型和单例对象不一样,它是一种类型,每一个引用v都有一个单例类型v.type,它只有2个可能的值:v和null,它表示的是当前对象的类型
  * 单例类型用的最多的是在链式调用中:如下
  */

class F {
  private var name: String = null

  def setName(name: String): this.type = {
    this.name = name
    this //返回调用对象
  }
}

class G extends F {
  private var age: Int = 0

  def setAge(age: Int) = {
    this.age = age
    this
  }
}

val f: F = new F
val g: G = new G
g.setName("aaa").setAge(22); //setName的返回类型不加this.type无法执行
g.setAge(22).setName("bbb")

/**
  * setName的返回类型不加this.type无法执行
  * 原因是执行setName时返回this,scala推荐为A类,修改返回类型为单例类型,返回类型就为g.type
  */


//########################### 16.4 类型投影 #################################
/**
  * class A{
  * class B
  * }
  * val a1 = new A
  * val a2 = new A
  * scala中内部类是属于实例的,a1.B与a2.B不是一个类型
  * 类型投影定义为A#B,表示任何A的B
  */

//########################### 16.5 类型别名 #################################
/**
  * 可以通过type关键字来创建一个简单的别名:
  * 类型别名必须被嵌套在类或者对象中,不能出现在scala文件的顶层
  */
class Document {
  type Index = mutable.HashMap[String, (Int, Int)]
}

val d = new Document
val index = new d.Index




//########################### 16.6 结构类型 #################################

/**
  * 任何具备append方法(且append参数是String,返回类型是Any)的类的实例都可以调用appendLines方法
  * 是通过反射实现的
  */
def appendLines(target: {def append(str: String): Any}, lines: Iterable[String]): Unit = {
  for (item <- lines) {
    target.append(item)
    target.append("\n")
  }
}

val lines = Array("aa", "bb", "cc")
val sb = new StringBuilder
appendLines(sb, lines)
sb


//########################### 16.7 复合类型 #################################


trait X1;

trait X2;

def test(x: X1 with X2) = println("ok")

//1.匿名子类
test(new X1 with X2)

//2.实际子类
class H extends X1 with X2

test(new H)

//3.类型type来声明
type X = X1 with X2
def test2(x: X) = println("ok")

test(new H)

//########################### 16.8 中置类型 #################################
/**
  * 是一个带有2个类型参数的类型,如下可以表示Map[String,Int]
  */
val scoer: String Map Int = Map("Fred" -> 42)

//########################### 16.9 运行时反射 #################################
/**
  * 获取运行时类型信息
  */
typeTag[List[Int]]
//reflect.runtime.universe.TypeTag[List[Int]] = TypeTag[List[Int]]
typeOf[List[Int]]
//reflect.runtime.universe.Type = List[Int]

/**
  * 获取任意对象类型信息
  */
val ru = scala.reflect.runtime.universe

//T: ru.TypeTag表示存在一个T->ru.TypeTag的隐式转换
def getTypeTag[T: ru.TypeTag](obj: T) = ru.typeTag[T]

val list = List(1, 2, 3)
val theType = getTypeTag(list).tpe


val decls = theType.declarations.take(2)


//获取擦除类型后的类型信息
import scala.reflect._

val clsTag = classTag[List[Int]]
clsTag.runtimeClass // Class[_$1] = class scala.collection.immutable.List


val cls = classOf[List[Int]] //Class[List[Int]] = class scala.collection.immutable.List
//可通过Class对象获取信息
cls.getConstructors
cls.getDeclaredMethods


/**
  * 运行时类型实例化
  * 上面已经知道,Type可以获取为擦除的详尽类型信息,下面通过Type对象中的信息找到构造方法并实例化类型的一个对象
  */

val m = ru.runtimeMirror(getClass.getClassLoader)

val classPerson = ru.typeOf[Person].typeSymbol.asClass

val cm = m.reflectClass(classPerson)

val ctor = ru.typeOf[Person].declaration(ru.nme.CONSTRUCTOR).asMethod

val ctorm = cm.reflectConstructor(ctor)

val p = ctorm(1, "Mike")


val nameTermSymb = ru.typeOf[Person].declaration(ru.newTermName("name")).asTerm

val im = m.reflect(p)

val nameFieldMirror = im.reflectField(nameTermSymb)

nameFieldMirror.get

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值