/**
* 第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