整体类层级
Scala 中,所有的类都继承自一个共同的超类,Any。因此所有定义在Any中的方法称为通用方法,任何对象都可以调用。并且在层级的最底层定义了Null和Nothing,作为所有类的子类。
类层级

可以看到,顶层类型为Any,下面分为两个大类,AnyVal包含了所有值类,AnyRef包含了所有引用类。
值类共包含 9 种:Byte, Short, Char, Int, Long, Float, Double, Boolean, 和 Unit。前 8 中与 Java 中的原始类型一致,在运行时都变现为 Java 原始类型。Unit等价于 Java 中的void类型,表示一个方法并没有返回值,而它的值只有一个,写作()。
引用类对应于 Java 中的Object,AnyRef只是java.lang.Object的别名,因此所有 Scala 或 Java 中编写的类都是AnyRef的子类。
Any中定义了一下多个方法:
final def ==(that: Any): Boolean
final def !=(that: Any): Boolean
def equals(that: Any): Boolean
def ##: Int
def hashCode: Int
def toString: String
因此所有对象都能够调用这些方法。
原始类的实现方式
Scala 与 Java 以同样的方式存储整数:以 32 位数字存放。这对在 JVM 上的效率以及与 Java 库的互操作性都很重要。标准的操作如加减乘除都被实现为基本操作。
但是,当整数需要被当做 Java 对象看待时,比如在整数上调用toString或将整数赋值给Any类型的变量,这时,Scala 会使用“备份”类java.lang.Integer。需要的时候,Int类型的整数能被透明转换为java.lang.Integer类型的装箱整数。
比如一个 Java 程序:
boolean isEqual(int x, int y){
return x == y;
}
System.out.println(isEqual(1,1)) // true
但是如果将参数类型改为Integer:
boolean isEqual(Integer x, Integer y){
return x == y;
}
System.out.println(isEqual(1,1)) // false
在调用isEqual时,整数 1 会被自动装箱为Integer类型,而Integer为引用类型,==在比较引用类型时比较的是引用相等性,因此结果为false。
但是在 Scala 中,==被设计为对类型表达透明。对于值类来说,就是自然(数学)的相等。对于引用类型,==被视为继承自Objct的equals方法的别名。而这个equals方法最初始被定义为引用相等,但被许多子类重写实现为自然理念上(数据值)的相等。因此,在 Scala 中使用==来判断引用类型的相等仍然是有效的,不会落入 Java 中关于字符串比较的陷阱。
而如果真的需要进行引用相等的比较,可以直接使用AnyRef类的eq方法,它被实现为引用相等并且不能被重写。其反义比较,即引用不相等的比较,可以使用ne方法。
底层类型
类层级的底部有两个类型,scala.Null和scala.Nothing。他们是用统一的方式来处理 Scala 面向对象类型系统的某些边界情况的特殊类型。
Null类是null引用对象的类型,它是每个引用类的子类。Null不兼容值类型,比如把null赋值给值类型的变量。
Nothing类型在 Scala 类层级的最底端,它是任何其他类型的子类型。并且该类型没有任何值,它的一个用处是标明一个不正常的终止,比如scala.sys中的error方法:
def error(message: String): Nothing
调用该方法始终会抛出异常。因为error方法的返回值是Nothing类型,我们可以简便的利用该方法:
def divide(x:Int, y:Int): Int =
if (y != 0) x / y
else error("can't divide by zero!") // 返回 Nothing,是 Int 的子类型,兼容
另外,空的列表Nil被定义为List[Nothing],因为List[+A]是协变的,这使得Nil可以是任何List[T]实例,T为任意类型。
Feedback
Was this page helpful?
Glad to hear it! Please tell us how we can improve.
Sorry to hear that. Please tell us how we can improve.