Scala中子类继承父类与JAVA一样,也使用extends关键字。继承的概念两种语言基本是一致的,都是表示子类可以从父类继承其属性与方法。子类可以派生自有的属性和方法,通过继承实现代码复用。此外,子类也可以覆盖父类的属性和方法。与JAVA中类似,如果某个类使用final修饰,或者属性或方法用final修饰,则该类无法被继承的,相应的属性与方法也是无法覆盖的。

class Sprint {

 private var name = "Sprint01"

 def getName = name

}

class SubSprint extends Sprint {

 private var point = "8"

 def getPoint = point

}

实例化SubSprint对象并调用对应get方法:

var subSprint = new SubSprint

subSprint.getName // 返回res0: String = Sprint01

subSprint.getPoint // 返回res1: String = 8

 

override关键字和super方法

Scala中子类可以通过override关键字来覆盖父类中的方法。同样,还可以在子类中使用super方法来显式调用父类方法。这两个关键字对应的处理逻辑与JAVA基本一致,对于JAVA开发者基本可以认为是等同的。下面是一个例子:

class Order {

   private var id = "901077890"

   def getId = id

}


//定义OrderDelivery类继承Order

class OrderDelivery extends Order {

   private var prefix = "DE_"

   private var address = "Shanghai Yangpu Rd.Yingkou No.1033 B1"

   def getAddress = address

   //需要使用override关键字来覆盖父类的getId方法

   override def getId = prefix + super.getId

}

var od = new OrderDelivery

println(od.getId) // 返回DE_901077890

 

isInstanceOfasInstanceOf方法

Scala中与JAVA类似,也有转型的概念,可以使用isInstanceOf判断对象是否指定类型的对象,并可以使用asInstanceOf将对象转换为指定类型。如果对象是nullisInstanceOf会返回falseasInstanceOf也会返回null值。如果对象为null值且未调用isInstanceOf判断,而直接使用asInstanceOf进行转换,此时会抛出异常。

class UserData

class SMS extends UserData

val d: UserData = new SMS

var s: SMS = null

 

println("d<UserData>.isInstanceOf[SMS]="+ d.isInstanceOf[SMS])

// 返回:d<UserData>.isInstanceOf[SMS]=true

 

if (d.isInstanceOf[SMS]) s =d.asInstanceOf[SMS]

println("s<SMS>.isInstanceOf[SMS]="+ s.isInstanceOf[SMS])

// 返回:s<SMS>.isInstanceOf[SMS]=true

println("s<SMS>.isInstanceOf[UserData]="+ s.isInstanceOf[UserData])

// 返回:s<SMS>.isInstanceOf[UserData]=true

 

getClassclassOf方法

Scala中的isInstanceOf方法只能判断对象是否某个类型,但不能精确判断对象就是指定类的对象。如果某些场景下需要精确判断对象是否派生自指定类,可以使用getClassclassOf方法实现。示例如下:

val d: UserData = new SMS

var s = d.asInstanceOf[SMS]

d.isInstanceOf[UserData] // Boolean = true

d.isInstanceOf[SMS] // Boolean = true

s.getClass == classOf[UserData] // Boolean= false

s.getClass == classOf[SMS] // Boolean =true

 

模式匹配与类型判断

模式匹配通过精简的方式来实现类型判断,功能上与isInstanceOf一致。

d match {

   case e: SMS => println("d match SMS")

   case e: UserData => println("d match UserData")

   case _  =>println("unknown type")

}

 

protected修饰符

Scala中的protected修饰符含义与JAVA一致,用来修饰属性和方法,表示对应资源可由子类访问。还可以用protected[this]来限制只能在当前子类对象中访问父类的属性与方法,而不允许调用其它传入的子类对象中父类的资源。

class Msg(id: String) {

   protected[this] var secretKey: String = id + "SECRET@9Y6"

}

 

class VoiceMsg(id: String) extends Msg(id:String) {

   def localSecret = println("SecretKey of current instance: " +secretKey)

   def remoteSecret(v: VoiceMsg) {

       println("local secret: " + secretKey)

       println(" remote secret: " + v.secretKey)

    }

}

编译时会报以下错误:

Error:(9, 40) value secretKey is not amember of VoiceMsg

println(" remote secret: " +v.secretKey)

 

调用父类构造器

Scala中每个类可以有一个主构造器和任意多个辅助构造器,而每个辅助构造器第一行都必须是调用其他辅助构造器或主构造器;因此子类的辅助构造器中无法直接调用父类构造器。如果在某些设计模式中需要直接调用,可以采用如下语法:

class Order(val userId: String, valorderId: Int)

 

// userIdorderId不需要加varval修饰,通过主构造器直接调用父类构造器

class Item(userId: String, orderId: Int,var price: Double) extends Order(userId, orderId) {

 def this(userId: String) {

   this(userId, 0, 0.00)

  }

 def this(orderId: Int) {

    this("USR9008X10", orderId, 0.00)

  }

}

即只能在子类主构造器中调用父类构造器。此外不能用valvar修饰子类的主构造器入参,否则就变成override了。

 

匿名内部类

Scala中的匿名内部类机制与JAVA类似,很常见且应用很广。参考以下示例:

// 定义抽象类Producer

abstract class Producer(protected valtopic: String) {

   def send: String = "AbstractProducer send msg with topic " +topic

}

// 创建Producer类型的匿名类

var mp = new Producer("phone") {

   override def send : String = "AnonymousProducer send msg with topic" + topic

}

// 定义方法,入参为匿名类实例

def sendMsg(p : Producer): Unit = {

   println(p.send)

}

sendMsg(mp) // 返回AnonymousProducer send msg with topic phone

 

抽象类

JAVA中概念类似,进行系统设计时可以先定义抽象类及对应方法签名,由具体实现时的子类型来覆盖,这些仅有方法签名不含实现的就是抽象方法。而一个类中如果包含象方法,那么声明类时需要用abstract关键字,而且抽象类是不可实例化的。此外在子类中覆盖抽象父类中的抽象方法时,不需要使用override关键字。

// 定义抽象类Producer

abstract class Producer(protected valtopic: String) {

   def send: String = "AbstractProducer send msg with topic " +topic

}

// 对抽象类进行实现并覆盖抽象方法

class KafkaProducer(topic : String)extends Producer(topic) {

   override def send : String = "KafkaProducer send msg with topic" + topic

}

// KafkaProducer实例化

var kp = newKafkaProducer("Logger")

kp.send // 返回KafkaProducer send msg with topic Logger

 

抽象属性

如果父类中定义属性,但没有给出初始值,则认为该属性为抽象属性。这个特性是Scala中比较特殊的,与JAVA差异较大,JAVA中的抽象大多情况下仅针对方法级别。抽象属性意味着scala会根据默认规则,对varval类型的属性生成对应的gettersetter方法,但父类中是没有该属性的,因此子类必须定义自己的具体属性,并覆盖抽象属性,此时不需要使用override关键字。

// 定义抽象类Producer

abstract class Producer(protected valtopic: String) {

 val startIdx: Integer

}

// 对抽象类进行实现并覆盖抽象方法

class KafkaProducer(topic : String) extendsProducer(topic) {

 val startIdx : Integer = 1000

}

// KafkaProducer实例化

var kp = newKafkaProducer("Logger")

kp.startIdx // res1: Integer = 1000