16.Scala-高级类型
第16章 高级类型
16.1 类型与类的区别
class A{} object TypeSyllabus { def main(args: Array[String]): Unit = { import scala.reflect.runtime.universe._ println(typeOf[A]) } }
同样scala里获取类(Class)信息也很便捷,类似:
class A{} object TypeSyllabus { def main(args: Array[String]): Unit = { import scala.reflect.runtime.universe._ println(typeOf[A]) println(classOf[A]) } }
尖叫提示:注意,typeOf 和 classOf 方法接收的都是类型符号(symbol),并不是对象实例。
16.2 classOf 与 getClass 的区别
获取Class时的两个方法: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],但是去比较的话,这两个类型是equals为true的。
这种细微的差别,体现在类型赋值时,因为java里的 Class[T]是不支持协变的,
所以无法把一个 Class[_ < : A] 赋值给一个 Class[A]。
scala> class A defined class A scala> val a = new A a: A = A@663bb8ef scala> a.getClass res2: Class[_ <: A] = class A scala> classOf[A] res3: Class[A] = class A scala> typeOf[A] <console>:15: error: not found: value typeOf typeOf[A] ^ scala> import scala.reflect.runtime.universe._ import scala.reflect.runtime.universe._ scala> typeOf[A] res5: reflect.runtime.universe.Type = A
16.3 单例类型
scala> object A
defined object A
scala> A.getClass res2: Class[_ <: A.type] = class A$
scala> typeOf[A.type] res0: reflect.runtime.universe.Type = A.type
scala> val a : A.type = A a: A.type = A$@e044b4a scala> def foo() : A.type = A foo: ()A.type
scala> class A scala> val a = new A
scala> typeOf[a.type] res0: reflect.runtime.universe.Type = a.type
scala> val x:a.type = a
x: a.type = A@6738694b
scala> val x:a.type = a2 <console>:13: error: type mismatch; found : a2.type (with underlying type A) required: a.type
scala> typeOf[a.type] == typeOf[A] // a.type 与 A 不是同一个类型 res2: Boolean = false
scala> typeOf[a.type] == typeOf[a2.type] // a.type 与 a2.type 也不同 res1: Boolean = false
scala> typeOf[a.type] <:< typeOf[A] // a.type 是 A 类型的子类型 res5: Boolean = true
class A { private var name:String=null def setName(name:String)={ this.name = name this // 返回调用对象 } } class B extends A{ private var sex:String = null def setAge(sex:String)={ this.sex=sex this } } object Main1 extends App{ val a:A = new A val b:B = new B // b.setName("WangBa").setAge("woman") // 无法执行 print(b) b.setAge("WangBa").setName("woman") // 可以执行 print(b) //unit16.B@566776adunit16.B@566776ad }
def setName(name:String):this.type ={ this.name = name this // 返回调用对象 }
16.4 类型投影
在scala里,内部类型(排除定义在object内部的),想要表达所有的外部类A实例路径下的B类型,即对 a1.B 和 a2.B及所有的 an.B类型找一个共同的父类型,这就是类型投影,用 A#B的形式表示。
A#B
/ \
/ \
a1.B a2.B
我们回头来对比一下scala里的类型投影与java里的内部类型的概念,java里的内部类型在写法上是 Outter.Inner 它其实等同于scala里的投影类型 Outter#Inner,java里没有路径依赖类型的概念,比较简化。
16.5 类型别名
可以通过type关键字来创建一个简单的别名,类型别名必须被嵌套在类或者对象中,不能出现在scala文件的顶层:
import scala.collection.mutable.HashMap class Document { import scala.collection.mutable._ type Index = HashMap[String, (Int, Int)] def play(x: Index): Unit ={} } object Main extends App{ type Index = HashMap[String, (Int, Int)] val d = new Document val m = new HashMap[String, (Int, Int)] val m1 = new Index d.play(m) d.play(m1) }
16.6 结构类型
结构类型是指一组关于抽象方法、字段和类型的规格说明,你可以对任何具备append方法的类的实例调用appendLines方法,
这种方式比定义特质更加灵活,是通过反射进行调用的:
class Structure { def play() = println("play方法调用了") } object HelloStructure { def main(args: Array[String]): Unit = { type X = {def play(): Unit} //type关键字是把 = 后面的内容命名为别名。 def init(res: X) = res.play //本地方法 init(new { def play() = println("Played") }) init(new { def play() = println("Play再一次") }) object A { def play() { println("A object play") } } init(A) val structure = new Structure init(structure) } }
总结:
结构类型,简单来说,就是只要是传入的类型,符合之前定义的结构的,都可以调用。
16.7 复合类型
class A extends B with C with D with E
应做类似如下形式解读:
class A extends (B with C with D with E)
T1 with T2 with T3 …
这种形式的类型称为复合类型(compound type)或者也叫交集类型(intersection type)。
也可以通过type的方式声明符合类型:
type X = X1 with X2
16.8 中置类型
中置类型是一个带有两个类型参数的类型,以中置语法表示,比如可以将Map[String, Int]表示为:
val scores: String Map Int = Map("Fred" -> 42)
16.9 自身类型
self => 这句相当于给this起了一个别名为self:
class A { self => //this别名 val x=2 def foo = self.x + this.x }
self不是关键字,可以用除了this外的任何名字命名(除关键字)。就上面的代码,在A内部,
可以用this指代当前对象,也可以用self指代,两者是等价的。
它的一个场景是用在有内部类的情况下:
class Outer { outer => val v1 = "here"
class Inner { println(outer.v1) // 用outer表示外部类,相当于Outer.this } }
对于this别名 self =>这种写法形式,是自身类型(self type)的一种特殊方式。self在不声明类型的情况下,
只是this的别名,所以不允许用this做this的别名。
16.10 运行时反射
scala编译器会将scala代码编译成JVM字节码,编译过程中会擦除scala特有的一些类型信息,
在scala-2.10以前,只能在scala中利用java的反射机制,
但是通过java反射机制得到的是只是擦除后的类型信息,
并不包括scala的一些特定类型信息。从scala-2.10起,
scala实现了自己的反射机制,我们可以通过scala的反射机制得到scala的类型信息。
给定类型或者对象实例,通过scala运行时反射,可以做到:
1)获取运行时类型信息;
2)通过类型信息实例化新对象;
3)访问或调用对象的方法和属性等。
16.10.1获取运行时类型信息
scala运行时类型信息是保存在TypeTag对象中,编译器在编译过程中将类型信息保存到TypeTag中,
并将其携带到运行期。我们可以通过typeTag方法获取TypeTag类型信息。
import scala.reflect.runtime.universe._ val typeTagList = typeTag[List[Int]]//得到了包装Type对象的TypeTag对象 println(typeTagList) 或者使用: typeOf[List[Int]]//直接得到了Type对象
尖叫提示:Type对象是没有被类型擦除的
我们可以通过typeTag得到里面的type,再通过type得到里面封装的各种内容:
import scala.reflect.runtime.universe._ val typeTagList = typeTag[List[Int]] println(typeTagList) println(typeTagList.tpe) println(typeTagList.tpe.decls.take(10))
16.10.2运行时类型实例化
我们已经知道通过Type对象可以获取未擦除的详尽的类型信息,
下面我们通过Type对象中的信息找到构造方法并实例化类型的一个对象:
class Person(name:String, age: Int) { def myPrint() = { println(name + "," + age) } } object PersonMain extends App{ override def main(args: Array[String]): Unit = { //得到JavaUniverse用于反射 val ru = scala.reflect.runtime.universe //得到一个JavaMirror,一会用于反射Person.class val mirror = ru.runtimeMirror(getClass.getClassLoader) //得到Person类的Type对象后,得到type的特征值并转为ClassSymbol对象 val classPerson = ru.typeOf[Person].typeSymbol.asClass //得到classMirror对象 val classMirror = mirror.reflectClass(classPerson) //得到构造器Method val constructor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod //得到MethodMirror val methodMirror = classMirror.reflectConstructor(constructor) //实例化该对象 val p = methodMirror("Mike", 1) println(p) } }
16.10.3运行时类成员访问
class Person(name:String, age: Int) { def myPrint() = { println(name + "," + age) } } object PersonMain extends App{ override def main(args: Array[String]): Unit = { //获取Environment和universe val ru = scala.reflect.runtime.universe //获取对应的Mirrors,这里是运行时的 val mirror = ru.runtimeMirror(getClass.getClassLoader) //得到Person类的Type对象后,得到type的特征值并转为ClassSymbol对象 val classPerson = ru.typeOf[Person].typeSymbol.asClass //用Mirrors去reflect对应的类,返回一个Mirrors的实例,而该Mirrors装载着对应类的信息 val classMirror = mirror.reflectClass(classPerson) //得到构造器Method val constructor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod //得到MethodMirror val methodMirror = classMirror.reflectConstructor(constructor) //实例化该对象 val p = methodMirror("Mike", 1) println(p) //反射方法并调用 val instanceMirror = mirror.reflect(p) //得到Method的Mirror val myPrintMethod = ru.typeOf[Person].decl(ru.TermName("myPrint")).asMethod //通过Method的Mirror索取方法 val myPrint = instanceMirror.reflectMethod(myPrintMethod) //运行myPrint方法 myPrint() //得到属性Field的Mirror val nameField = ru.typeOf[Person].decl(ru.TermName("name")).asTerm val name = instanceMirror.reflectField(nameField) println(name.get) } }
笔记:
package unit16 class Person(name:String, age: Int) { def myPrint() = { println(name + "," + age) } } object PersonMain extends App{ override def main(args: Array[String]): Unit = { /* Scala通过反射,实例化对象 */ //得到JavaUniverse用于反射 val ru = scala.reflect.runtime.universe //得到一个JavaMirror,一会用于反射Person.class val mirror = ru.runtimeMirror(getClass.getClassLoader) //得到Person类的Type对象后,得到type的特征值并转为ClassSymbol对象 val classPerson = ru.typeOf[Person].typeSymbol.asClass //得到classMirror对象 val classMirror = mirror.reflectClass(classPerson) //得到构造器Method val constructor = ru.typeOf[Person].decl(ru.termNames.CONSTRUCTOR).asMethod //得到MethodMirror val methodMirror = classMirror.reflectConstructor(constructor) //实例化该对象 val p = methodMirror("Mike", 1) println(p) //unit16.Person@7cbc3762 /* Scala通过反射,调用对象 */ val instanceMirror = mirror.reflect(p) //得到Method的Mirror val myPrintMethod = ru.typeOf[Person].decl(ru.TermName("myPrint")).asMethod //通过Method的Mirror索取方法 val myPrint = instanceMirror.reflectMethod(myPrintMethod) //运行myPrint方法 myPrint() //Mike,1 /* Scala通过反射,访问属性 */ val nameField = ru.typeOf[Person].decl(ru.TermName("name")).asTerm val name = instanceMirror.reflectField(nameField) println(name.get) //Mike } }
请你一定不要停下来 成为你想成为的人
感谢您的阅读,我是LXL