图释 11.1 Scala类层级图
51CTO编辑推荐:Scala编程语言专题
图释11.1展示了Scala的类层级的大纲。层级的顶端是类Any,定义了包含下列的方法:
- final def ==(that: Any): Boolean
- final def !=(that: Any): Boolean
- def equals(that: Any): Boolean
- def hashCode: Int
- def toString: String
因为每个类都继承自Any,Scala程序里的每个对象都能用==,!=或equals比较;用hashCode哈希;和用toString格式化。类Any里的等号和不等号方法,==和!=,被声明为final,因此它们不能在子类里面重载。实际上,==总是与equals相同,!=总是与equals相反。因此独立的类可以通过重载equals方法剪裁==或!=的意义。我们会在本章后面展示一个例子。
根类Any有两个子类:AnyVal和AnyRef。AnyVal是Scala里每个内建值类的父类。有九个这样的值类:Byte,Short,Char,Int,Long,Float,Double,Boolean和Unit。其中的前八个对应到Java的原始类型,它们的值在运行时表示成Java的原始值。Scala里这些类的实例都写成文本。例如,42是Int的实例,'x'是Char的实例,false是Boolean的实例。你不能使用new创造这些类的实例。这一点被“小伎俩”,值类都被定义为即是抽象的又是final的,强制贯彻。因此如果你写了:
- scala> new Int
你就会得到:
- < console>:5: error: class Int is abstract; cannot be instantiated
- new Int
- ˆ
另一个值类,Unit,大约对应于Java的void类型;被用作不返回任何有趣结果的方法的结果类型。Unit只有一个实例值,被写作(),在7.2节中讨论过。
正如第五章中解释过,值类支持作为方法的通用的数学和布尔操作符。例如,Int有名为+和*的方法,Boolean有名为||和&&的方法。值类也从类Any继承所有的方法。你可以在解释器里测试:
- scala> 42.toString
- res1: java.lang.String = 42
- scala> 42.hashCode
- res2: Int = 42
- scala> 42 equals 42
- res3: Boolean = true
注意,值类的空间是扁平的;所有的值类都是scala.AnyVal的子类型,但是它们不是互相的子类。代之以它们不同的值类类型之间可以隐式地互相转换。例如,需要的时候,类scala.Int的实例可以自动放宽(通过隐式转换)到类scala.Long的实例。
正如5.9节中提到过的,隐式转换还用来为值类型添加更多的功能。例如,类型Int支持以下所有的操作:
- scala> 42 max 43
- res4: Int = 43
- scala> 42 min 43
- res5: Int = 42
- scala> 1 until 5
- res6: Range = Range(1, 2, 3, 4)
- scala> 1 to 5
- res7: Range.Inclusive = Range(1, 2, 3, 4, 5)
- scala> 3.abs
- res8: Int = 3
- scala> (-3).abs
- res9: Int = 3
这里解释其工作原理:方法min,max,until,to和abs都定义在类scala.runtime.RichInt里,并且有一个从类Int到RichInt的隐式转换。当你在Int上调用没有定义在Int上但定义在RichInt上的方法时,这个转换就被应用了。类似的“助推器类”和隐式转换存在于其它的值类。隐式转换将在第21章讨论细节。
类Any的另一个子类是类AnyRef。这个是Scala里所有引用类的基类。正如前面提到的,在Java平台上AnyRef实际就是类java.lang.Object的别名。因此Java里写的类和Scala里写的都继承自AnyRef。存在AnyRef别名代替使用java.lang.Object名称的理由是,Scala被设计成可以同时工作在Java和.Net平台。在.NET平台上,AnyRef是System.Object的别名。如此说来,你可以认为java.lang.Object是Java平台上实现AnyRef的方式。因此,尽管你可以在Java平台上的Scala程序里交换使用Object和AnyRef,推荐的风格是在任何地方都只使用AnyRef。
Scala类与Java类不同在于它们还继承自一个名为ScalaObject的特别的记号特质。理念是ScalaObject包含了Scala编译器定义和实现的方法,目的是让Scala程序的执行更有效。到现在为止,Scala对象包含了单个方法,名为$tag,用于内部以提速模式匹配。
【相关阅读】