Null与Nothing
scala类型系统以Any
为根,分为AnyRef
和AnyVal
两个分支体系,在AnyRef
分支的最底层,有个Null类型的特殊类型,它被当作是所有AnyRef
类型的子类型。
更进一步在两个分支共同的最底层类型是Nothing类型,它被当作所有AnyRef
和AnyVal
类型的子类型。
Null类型只有一个唯一的值:null,可以被赋给所有的AnyRef类型变量
scala> val s:String = null
s: String = null
但null不可以赋值给AnyVal类型:
scala> val i:Int = null
<console>:7: error: type mismatch;
found : Null(null)
required: Int
注意,不要被Unit值类型在赋值时的障眼法给骗了,以为null可以被赋给Unit
scala> val u:Unit = null
u: Unit = ()
实际上把任何表达式结果不是Unit类型的表达式赋给Unit类型变量,都被转为 { expr; () }
,所以上面的等同于{null; ()}
把最终得到的()
赋给了u变量。
Null在类型推导时只能被造型为AnyRef分支下的类型,不能造型为AnyVal分支下的类型,不过我们显式的通过asInstanceOf
操作却又是可以把null造型为AnyVal类型的:
scala> null.asInstanceOf[Int]
res0: Int = 0
这是因为asInstanceOf操作导致了装箱拆箱的行为,在值类型的一些细节里有提到过;
val i = null.asInstanceOf[Int]
// 类似于java里的
int i = (int)((Integer)null);
先装箱Int为引用类型,null被造型成了引用类型的Int(java.lang.Integer),然后又做了一次拆箱,把一个为null的Integer类型变量造型成Int值类型,但在拆箱这一点处理上,体现了scala与java的不同:
// java里,编译通过,运行失败,空指针异常
int i = (int)((Integer)null);
// scala里,把值为null的Integer拆箱为值类型Int是ok的,得到Int的默认值0
val i = null.asInstanceOf[java.lang.Integer].asInstanceOf[Int]
在java里基本类型(primitive type) 与引用类型是有明确差异的,虽然提供了自动装箱拆箱的便捷,但在类型上两者是不统一的;而scala里修正这一点,Int类型不再区分int/Integer,类型一致,所以值为null的Integer在通过asInstanceOf[Int]时被当作一个未初始化的Int对待,返回了一个默认值Int(注:asInstanceOf不改变原值,返回一个新值)
这一点对自定义的值类型也一样
scala> class A(val i:Int) extends AnyVal
defined class A
scala> null.asInstanceOf[A]
res18: A = A@0
Nothing类型的特殊之处在于它没有对应的值,这个类型存在的意义或许只是为了类型推导:
scala> def foo = throw new RuntimeException
foo: Nothing
因为scala里每个表达式都有结果,也包括throw语句,它的返回类型是Nothing,而实际运行中会导致线程终止,所以只是编译时用于类型推导
scala> def foo(i:Int) = if (i==100) "OK" else throw new RuntimeException
foo: (i: Int)String
上面if分支返回String类型,而else分支是Nothing,返回值类型是String与Nothing在类型树上的最小公共父类型,因为Nothing是String的子类型,所以直接返回了 String类型。
另外Nothing可用在泛型情况下:
scala> val l:List[Int] = List[Nothing]()
l: List[Int] = List()
因为List[+A]定义是协变的,所以List[Nothing]是List[Int]的子类,但List[Null]不是List[Int]的子类
scala> val l:List[Int] = List[Null]()
<console>:7: error: type mismatch;
found : List[Null]
required: List[Int]
Null本来是不应该存在的东西。只是为了和java兼容
学习了