Scala进阶之路-Scala中的高级类型
作者:尹正杰
版权声明:原创作品,谢绝转载!否则将追究法律责任。
一.类型(Type)与类(Class)的区别
在Java里,一直到jdk1.5之前,我们说一个对象的类型(type),都与它的class是一一映射的,通过获取它们的class对象,比如 String.class, int.class, obj.getClass() 等,就可以判断它们的类型(type)是不是一致的。简单的说Type是用来描述类的,而Class是用来描述类的,因此Tpye范围要比Class描述的范围要更大一些!
而到了jdk1.5之后,因为引入了泛型的概念,类型系统变得复杂了,并且因为jvm选择了在运行时采用类型擦拭的做法(兼容性考虑),类型已经不能单纯的用class来区分了,比如 List<String> 和 List<Integer> 的class 都是 Class<List>,然而两者类型(type)却是不同的。泛型类型的信息要通过反射的技巧来获取,同时java里增加了Type接口来表达更泛的类型,这样对于 List<String>这样由类型构造器和类型参数组成的类型,可以通过 Type 来描述;它和 List<Integer> 类型的对应的Type对象是完全不同的。
在Scala里,类型系统又比java复杂很多,泛型从一开始就存在,还支持高阶的概念(后续会讲述)。所以它没有直接用Java里的Type接口,而是自己提供了一个scala.reflect.runtime.universe.Type(2.10后)。
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 import scala.reflect.runtime.universe._ 9 10 class Teacher(name:String,age:Int){ 11 12 } 13 14 object AdvancedType { 15 def main(args: Array[String]): Unit = { 16 /** 17 * 注意,typeOf 和 classOf 方法接收的都是类型符号(symbol),并不是对象实例。 18 */ 19 val typeInfo = typeOf[Teacher] //在scala里获取类型信息是比较便捷的 20 println(typeInfo) 21 22 val classInfo = classOf[Teacher] //同样scala里获取类(Class)信息也很便捷 23 println(classInfo) 24 } 25 } 26 27 28 /* 29 以上代码执行结果如下: 30 cn.org.yinzhengjie.Teacher 31 class cn.org.yinzhengjie.Teacher 32 */
二.classOf与getClass的区别
获取Class时的两个方法:classOf 和 getClass。
这种细微的差别,体现在类型赋值时,因为java里的 Class[Teacher]是不支持协变的,所以无法把一个Class[_ < : Teacher] 赋值给一个 Class[Teacher]。
三.结构类型
结构类型是指一组关于抽象方法、字段和类型的规格说明,你可以对任何具备play方法的类的实例调用play方法,这种方式比定义特质更加灵活,是通过反射进行调用的。简单来说,就是只要是传入的类型,符合之前定义的结构的,都可以调用。
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 class Structure { 9 def play() = println("play方法调用了") 10 } 11 12 13 14 object AdvancedType extends App { 15 /** 16 * type关键字是把 = 后面的内容命名为别名。 17 */ 18 type X = { 19 def play(): Unit 20 } 21 22 /** 23 * 定义本地方法,将X类型传入 24 */ 25 def init(res: X) = { 26 res.play 27 } 28 29 /** 30 * 调用init的方法,需要传入一个实现X对象的paly方法 31 */ 32 init(new { 33 def play() = println("Play再一次") 34 }) 35 36 37 /** 38 * 结构类型,简单来说,就是只要是传入的类型,符合之前定义的结构的,都可以调用。 39 */ 40 object A { 41 def play() { 42 println("A object play") 43 } 44 } 45 46 init(A) 47 48 val structure = new Structure 49 init(structure) 50 } 51 52 53 /* 54 以上代码执行结果如下: 55 Play再一次 56 A object play 57 play方法调用了 58 */
四.中置类型
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 object AdvancedType extends App { 9 /** 10 * 中置类型是一个带有两个类型参数的类型,以中置语法表示,比如可以将Map[String, Int]表示为: 11 */ 12 val scores: String Map Int = Map("yinzhengjie" -> 100) 13 println(scores) 14 } 15 16 17 /* 18 以上代码执行结果如下: 19 Map(yinzhengjie -> 100) 20 */
五.自身类型
对于this别名 yinzhengjie=>这种写法形式,是自身类型(yinzhengjie type)的一种特殊方式。yinzhengjie在不声明类型的情况下,只是this的别名,所以不允许用this做this的别名。案例如下:
1 /* 2 @author :yinzhengjie 3 Blog:http://www.cnblogs.com/yinzhengjie/tag/Scala%E8%BF%9B%E9%98%B6%E4%B9%8B%E8%B7%AF/ 4 EMAIL:y1053419035@qq.com 5 */ 6 package cn.org.yinzhengjie 7 8 class A { 9 /** 10 * yinzhengjie => 这句相当于给this起了一个别名叫yinzhengjie, 11 * 注意 : yinzhengjie并不是关键字,可以用除了this外的任何名字命名(除关键字)。 12 */ 13 yinzhengjie => 14 val x = 100 15 def foo = yinzhengjie.x + this.x 16 } 17 18 19 /** 20 * 注意,这里的yinzhengjie是给外部的Outer起了一个别名叫做yinzhengjie 21 */ 22 class Outer { yinzhengjie => 23 val v1 = "here" 24 //定义一个Scala内部类 25 class Inner { 26 val v1 = "there" 27 println(yinzhengjie.v1) // 用yinzhengjie表示外部类(起了个别名),相当于Outer.this.v1 28 } 29 new Inner 30 println(this.v1) 31 println(Outer.this.v1) 32 } 33 34 35 object AdvancedType extends App { 36 new Outer 37 38 val res = new A 39 println(res.foo) 40 } 41 42 43 /* 44 以上代码执行结果如下: 45 here 46 here 47 here 48 200 49 */
六.运行时反射
关于Scala高级类型还有很多,我这里就不一一列举啦,比如:复合类型,类型别名,类型投影,单例类型等等。对了,关于反射的笔记请参考:https://www.cnblogs.com/yinzhengjie/p/9385123.html