讲面向对象可少不了继承和多态以及接口,它们让面向对象变得优雅。
在讲继承,多态,接口之前,我们先来讲一下Scala里的统一类型(Unified Types)。

类型系统

 

Scala类型系统图(引用自scala-lang.org)

Any 是Scala里所有类型的父类。它定义了 equals, hashCode,toString 的方法。然后在Any下边分为了值类型的父类AnyVal,它下边有scala内部定义好的9中基本值类型。Any下还有引用类型的父类AnyRef,其中有Scala预先定义好的List,Array… 以及所有我们定义的其它类型。

这个类型图里我们需要注意的是:

  1. AnyRef 对应于Java里的Object,因为Java里的基本值类型不是对象。
  2. Unit 是一个基本值类型,它的实例只有一个就是 () 空的括号。Scala里方法必须有返回值,当你没有什么要返回的时候,就返回Unit。

还有两个特别要注意的,就是 Null 和 Nothing,对于Java程序员来说这可能不好理解。

Null

Null是一种类型,只有一个值就是字面值 null。虽然你可以给所有的引用类型赋值为null,但是在Scala里最好不要用null。因为在Scala里有更好的选择来对应空值。Null类型主要是Scala为了和其他 JVM 语言互操作用的一个类型。

Nothing

Nothing也是一种类型,但是它没有任何实例。一般用来表示程序的非正常退出。因为Nothing是所有类型的子类,所以它可以向上转型给任意类型。我们看个例子,我们想要定义一个 fixMe 的方法,来放在代码里我们需要稍后修改的地方:

scala> def fixMe = throw new Exception()
fixMe: Nothing

我们定义了一个方法 fixMe,这个方法里直接抛出一个异常。那么这个方法的返回值是什么呢?注意抛出的异常并不是返回值。抛出异常只是打断了程序正常执行流程。如果我们想要返回一个异常,我们可以这样定义:

scala> def fixMe = new Exception
fixMe: Exception

这时Scala编译器正确识别出了返回值是Exception。 回到之前的问题,之前我们定义的那个方法返回值是什么呢?编译器给我们的答案是Nothing。 你可能会问,为什么不是Unit呢?我们看一下这个例子:

def toString(something:Any):String = fixMe

如果 fixMe 返回值类型是Unit,那么这个编译会出错。但是如果返回值类型是Nothing则不会出错。而且Scala的预定义库里的error方法是这么定义的:

def error(message:String): Nothing = throw new RuntimeException(message)

这样的定义方便我们这么使用:

def devide(a: Int, b: Int): Int = {
  if (b != 0) a / b else sys.error("test")
}

scala默认帮我们引用了java.lang.,scala., Predef._ 这几个包。而error 这个方法是定义在scala.sys 下的。

继承

Scala里类的继承用的关键字是extends,如果我们定义父类,那么就直接继承自 AnyRef 类,我们看个例子:

package www.rethink.fun
class People(val name:String) {
  def hi=s"Hi,my name is $name"
}
class Student(n:String,val school:String)extends People(n){
  def goSchool=s"I'm going to $school"
}

object Test extends App{
  val student = new Student("CoCo","QingHua University")
  println(student.hi)
  println(student.goSchool)
}

这里需要注意的是如何调用父类的构造函数。我们把Student的构造函数的参数 n 传递给父类 People 的构造函数的name参数。还有就是构造顺序是先构造父类,后构造子类。

重载方法

在Scala里成员方法可以被重载。重载时必须加override关键字,这样就能防止无意重载了父类的方法。在子类 里如果想明确访问父类的方法可以加关键字super

package www.rethink.fun
class People(val name:String) {
  def hi=s"Hi,my name is $name."
}
class Student( name:String,val school:String)extends People(name){
  override def hi=super.hi+s" I'm going to $school"   //通过super关键字来访问父类
}

object Test extends App{
  val student = new Student("CoCo","QingHua University")
  println(student.hi)                  //Hi,my name is CoCo. I'm going to QingHua University
}

发表评论

电子邮件地址不会被公开。 必填项已用*标注

%d 博主赞过: