Scala开发教程(44): Scala的类层次关系

jerry Scala 2015年11月25日 收藏

前面我们介绍了Scala的类的继承,本篇我们介绍Scala语言自身定义的类的层次关系,在Scala中,所有的类都有一个公共的基类称为Any,此外还定义了所有类的子类Nothing,下面的图给出的Scala定义的类层次关系的一个概要:
20131201001

由于所有的类都继承自Any,因此Scala中的对象都可以使用==,!=,或equals来比较,使用##或hashCode给出hash值,使用toString 转为字符串。Any的==和!=定位为fianl,因此不可以被子类重载。==实际上和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的实例。值类型都被定义为即是抽象的又是final的,你不能使用new创造这些类的实例。

scala> new Int
<console>:8: error: class Int is abstract; cannot be instantiated
              new Int
              ^

scala> 

另一个值类,Unit,大约对应于Java的void类型;被用作不返回任何有趣结果的方法的结果类型。Unit只有一个实例值,被写作().

值类支持作为方法的通用的数学和布尔操作符。例如,Int有名为+和*的方法,Boolean有名为||和&&的方法。值类也从类Any继承所有的方法。你可以在解释器里测试:

scala> 42 toString
res3: String = 42
scala> 42.hashCode
res6: Int = 42

可以看到Scala的值类型之间的关系是扁平的,所有的值类都是scala.AnyVal的子类型,但是它们不是互相的子类。代之以它们不同的值类类型之间可以隐式地互相转换。例如,需要的时候,类scala.Int的实例可以自动放宽(通过隐式转换)到类scala.Long的实例。隐式转换还用来为值类型添加更多的功能。例如,类型Int支持以下所有的操作:

scala> 42 max 43
res0: Int = 43

scala> 42 min 43
res1: Int = 42

scala> 1 until 5
res2: scala.collection.immutable.Range = Range(1, 2, 3, 4)

scala> 1 to 5 
res3: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3, 4, 5)

scala> 3.abs
res4: Int = 3

scala> (-3).abs
res5: Int = 3

这里解释其工作原理:方法min,max,until,to和abs都定义在类scala.runtime.RichInt里,并且有一个从类Int到RichInt的隐式转换。当你在Int上调用没有定义在Int上但定义在RichInt上的方法时,这个转换就被应用了。
类Any的另一个子类是类AnyRef。这个是Scala里所有引用类的基类。正如前面提到的,在Java平台上AnyRef实际就是类java.lang.Object的别名。因此Java里写的类和Scala里写的都继承自AnyRef。如此说来,你可以认为java.lang.Object是Java平台上实现AnyRef的方式。因此,尽管你可以在Java平台上的Scala程序里交换使用Object和AnyRef,推荐的风格是在任何地方都只使用AnyRef。

Scala类与Java类不同在于它们还继承自一个名为ScalaObject的特别的Marker Trait(Trait我们在后面再进一步解释)