Scala基础06:继承

Scala继承

继承是类的扩展

extends是Scala中实现继承的保留字:

class week extends month{...}

说明:

week类继承了month类所有非私有成员。

week类是month类的子类,month类是week类的超类。

子类能重写超类的成员(具有相同名称和参数)。

和Java一样,若类被声明为final,则该类不可再被继承。若方法或字段被声明为final,则该方法不可再被重写。

注意:Scala中的final与Java中的final有一点不同,Java中final的字段是不可变的。Scala中没有。

object继承class

例:

class Student(name:String , age:Int ,val major : String) extends Person(name , age) {
  println("this is subclass of Person , major is :" + major)
}

单例对象同样能从类中继承,与类的继承语法相同:

object day extends week{...}

重写

Scala中使用override保留字进行方法、字段重写

class week extends month{
  override def firstday = {...}
}

override也可以用于类的主构造器参数:

class week(override val lastday:String) extends month{...}

子类的重写或修改Scala会检查其超类,但是,超类的修改并不会检查其子类。

例:

class Student(name:String , age:Int ,val major : String) extends Person(name , age) {
  println("this is subclass of Person , major is :" + major)
  override def toSting = "override toSting"
}

重写包括字段和方法,但参数不同的方法可以不重写

class month{ def secondday(m:String)={...}}

class week extends month{ def secondday ={...}}

规则:

重写 def

用val :利用val能重写超类用没有参数的方法(getter)

用def:子类的方法与超类方法重名

用var:同时重写getter、setter方法,只重写getter方法报错

重写val

用val:子类的一个私有字段与超类的字段重名,getter方法重写超类的getter方法

重写var

用var:且当超类的var是抽象的才能被重写,否则超类的var都会被继承

例:

class month{

val one = 25 //可在子类中用val重写

var two = 15 //不可在子类中用var重写,因为不是抽象的

var three:Int

def firstday =                               //可在子类中用val重写

def now =                                    //可在子类中用var重写

def now_ =

def lastday(m:Char)={}                //可在子类中用def重写

}

总结:

子类中,def只能重写超类的def,val能重写超类的val或不带参数的def,var只能重写超类中抽象的var或者超类的getter/setter对。

类型检查和转换

使用isInstanceOf方法测试对象的类是否继承于某个类。使用asInstanceOf方法将引用转换为子类的引用。

if(p.isInstanceOf[Employee]){
  val s = p.asInstanceOf[Employee]  // s的类型为Employee
  // ...
}

若p指向Employee类及其子类(比如Manager类)的对象。则p.isInstanceOf[Employee] 返回true。

若p为null,则p.isInstanceOf[Employee]将返回false,则p.asInstanceOf[Employee]将返回null。

若p不是一个Employee,则p.asInstanceOf[Employee]将抛出异常。

若需要判断 “p指向的就是一个Employee对象,不是其子类的对象。” 则可以使用:

if (p.getClass == classOf[Employee])

classOf方法定义在scala.Predef对象中,因此会被自动引入。

说明:对于类型检查和转换,Scala中更偏向于使用模式匹配。

Scala和Java的类型检查和转换

Scala Java
obj.inInstanceOf[C1] obj instanceof C1
obj.asInstanceOf[C1] (C1)obj
classOf[C1] C1.class

匿名子类

val alien = new Person("Fred"){
  def greeting = "Greetings , Earthling! My name is Fred"
}

抽象类

不能被实例的类叫做抽象类。

抽象类的某个或某几个成员没有被完整定义,这些没有被完整定义的成员称为抽象方法或抽象字段。

用abstract保留字标记抽象类。

abstract year{

val name: Array[String]  //抽象的val,带有一个抽象的getter方法

var num: Int  //抽象的var,带有抽象的getter/setter方法

def sign1 //没有方法体,就是一个抽象方法。

def sign2: Int //没有函数体,就是一个抽象函数。

}

只要类中有任意一个抽象成员,必须使用abstract标记。

重写抽象方法、抽象字段不需要使用override保留字。

抽象字段,即没有初始值的字段。

抽象方法,即没有方法体的方法。

保护

当一个类不希望被继承、拓展时,可在类声明前加上final保留字。

final class year{...}

当一个类的某些成员不希望被重写时,可以在成员声明前加上final保留字。

class year{

final def sign{...}

}

当超类中的某些成员需要被子类继承,又不想对子类以外成员可见时,在成员声明前加上protected保留字。

protected[this],将访问权限定于当前对象,类似于private[this]。

类中protected的成员对其子类可见,对其超类不可见:

class year{

protected def sign{...}

}

辨析:private与private[this]的区别。

继承与构造器

子类构造器的运行在超类构造器运行之后。

在超类的构造器中调用的成员被子类重写后,返回值可能不正确:

class month{

val num = 31

val days = new Array[Int](num)

}

class week extends month{

override val num = 7

}

val a=new week

构造week对象前先执行month的构造器,num被初始化为31,month为初始化days数组,调用num,但num被子类week重写了,但因为week构造器还没被调用,

此时num的值未被初始化,因而返回0,days被设置为长度为0的数组,month构造器运行

完毕,执行week构造器,num被初始化为7

解决方法:

将超类的val声明为final

将超类的val声明为lazy

在子类中使用提前定义语法

提前定义

在超类的构造器运行之前初始化子类的字段。

把需要提前定义的语句块放在extends与超类之间,并后接with保留字。

class week extends {override val num =7} with month{...}

提前定义中“=”右侧若需调用类中B成员时,除非B成员已在调用前提前定义:

class week extends{

override val num=7

override val num2=num+1 //允许,num已被提前定义

override val num4=num2+num3 //不允许,num3没有在之前提前定义

}with month{...}

特质

Java8中新增一个特性:default method ,可以在interface中实现的方法。

Scala特质类似Java 8的interface。

Scala类只能继承自一个父类,但可以由多个特质拓展而成。

Scala不支持多重继承,取而代之的是特质。

Trait可以作为工具方法混入到相关类中。

多重继承的问题

一个子类只能拥有一个超类,一个超类能拥有多个子类。

即:class week extends month,year是不合法的。

为什么?

若一个子类继承自不同的超类,不同的超类中同名成员子类不知如何处理。

多重继承产生菱形继承问题。

解决多重继承可能导致的问题消耗的资源远比多重继承产生的价值高

Scala使用特质达到类似多重继承的效果。

一个类可以扩展自一个或多个特质,一个特质可以被多个类扩展。

特质能限制被什么样的类所扩展。

所有Java interface都能当做是特质使用在Scala中。

当接口使用特质

trait Logger{

def log(msg:String)

}

实现

scala中没有implements,所以使用extends即可。

class ConsoleLogger extends Logger{

def log(msg:String){ println(msg) }

}

重写特质的方法,不需要override关键字。

特质中重写抽象方法

trait Logger{

def log(msg:String)

}

重写特质需要使用override。

trait TimestampLogger extends Logger{

override def log(msg:String){

super.log(new java.util.Date()+” ”+msg)

}

}

特质是Scala里代码复用的基础单元,封装了方法和字段的定义。

特质的定义使用保留字trait,具体语法与类定义相似,除了不能拥有构造参数。

trait reset{

def reset(m:Int,n:Int) = if(m >= n) 1

}

一旦特质被定义了,就可以混入(mixin)到类中。

class week extends reset {...}

当要混入多个特质时,利用with关键字:

class week extends reset with B with C {...}

特质的成员可以是抽象的,而且,不需要使用abstract声明。

同样的,重写特质的抽象方法无需给出override。

但是,多个特质重写同一个特质的抽象方法需给出override。

除了在类定义中混入特质以外,还可以在特质定义中混入特质:

trait reseting extends reset{...}

在对象构造时混入特质:

val five = new month with reseting

特质的构造是有顺序的:从左到右被构造。

构造器按如下顺序构造:

超类

父特质

第一个特质

第二个特质(父特质不重复构造)

如果class A extends B1 with B2 with B3....

那么,串接B1、B2、B3...等特质,去掉重复项且右侧胜出。

特质的应用

特质的一个主要应用方面在于接口,根据类已有的方法自动为类添加方法。

利用特质实现富接口:

构造一个具有少量抽象方法和大量基于抽象方法的具体方法的特质。

那么,只要把特质混入类中,通过类重写抽象方法后,类便自动获得大量具体方法。

trait Logger{

def log(msg:String)

def warn(msg:String) { log(“server”+msg) }

def server(msg:String) { log(“server”+msg) }

}

class week extends Logger{

def log(msg:String){println(msg)}

server(“HI”)

}

特质的另一个应用方面在于:为类提供可堆叠的改变(super保留字)

当为类添加多个互相调用的特质时,从最后一个开始进行处理。

在类中super.foo() 这样的方法调用是静态绑定的,明确是调用它的父类的 foo() 方法。

在特质中写下了 super.foo() 时,它的调用是动态绑定的。调用的实现讲在每一次特质被混入到具体类的时候才被决定。

因此,特质混入的次序的不同其执行效果也就不同。

abstract class IntQueue { def get(): Int;def put(x: Int) }

class BasicIntQueue extends IntQueue {

private val buf = new ArrayBuffer[Int]

def get() = buf.remove(0)

def put(x: Int) { buf += x }

}

trait Incrementing extends IntQueue {

abstract override def put(x: Int) {

super.put(x + 1)

}

}

trait Doubling extends IntQueue {

abstract override def put(x: Int) {

super.put(2 * x)

}

}

object TestClient extends App {

val queue1 = (new BasicIntQueue with Incrementing with Doubling)

//Doubling.put(2*2)->Incrementing.put(4+1)

queue1.put(2)

println(queue1.get())  //result is 5

val queue2 = (new BasicIntQueue with Doubling with Incrementing)

//Incrementing.put(2+1)->Doubling.put(2*3)

queue2.put(2)

println(queue2.get())  //result is 6

}

App特质只支持单线程。而普通的main可以支持多线程。

扩展类和特质

构造一个扩展了指定类和特质的类的对象,同时拥有对象定义中给出的所有特性

Scala文件访问

scala中访问文件需要使用scala.io.Source对象。

例:读取本地文件。

def main(args: Array[String]) {

// 访问文件

val file = Source.fromFile("D:\\scala-test.txt")

for(line <- file.getLines){

println(line)

}

}

若使用:

for(line <- file){

println(line)

}

则不会一行一行的读取数据,而是一个字一个字的读取并输出。

例:读取网络文件。

def main(args: Array[String]) {

// 访问网络URL

val file = Source.fromURL("http://www.baidu.com")

for(line <- file.getLines){

println(line)

}

}

时间: 2024-08-18 03:05:11

Scala基础06:继承的相关文章

scala 基础九 scala 类的扩展和继承extends override

1.scala 类的继承 package smart.iot //父类 animal 有三个参数 class animal(var name:String,var age:Int,var eat:String) { } //子类 panda 继承父类 animal class Panda( name:String, age:Int, eat:String,var blackeye:String) extends animal(name,age,eat) { } object load { def

Scala基础07:特质

多重继承的问题 多重继承产生菱形继承问题.解决多重继承可能导致的问题消耗的资源远比多重继承产生的价值高. 特质 Java8中新增一个特性:default method ,可以在interface中实现的方法.Scala特质类似Java 8的interface. Scala类只能继承一个父类,但可以由多个特质拓展而成.Scala不支持多重继承,取而代之的是特质.Trait可以作为工具方法混入到相关类中. Scala使用特质达到类似多重继承的效果.一个类可以扩展自一个或多个特质,一个特质可以被多个类

Spark入门到精通视频学习资料--第一章、Scala基础与实践

第一章.Scala基础与实践(3讲) Scala编程语言抓住了很多开发者的眼球.如果你粗略浏览Scala的网站,你会觉得Scala是一种纯粹的面向对象编程语言,而又无缝地结合了命令式和函数式的编程风格. 根据David Rupp在博客中的说法,Scala可能是下下一代Java. Scala有几项关键特性表明了它的面向对象的本质.例如,Scala中的每个值都是一个对象,包括基本数据类型(即布尔值.数字等)在内,连函数也是对象.另外,类可以被子类化,而且Scala还提供了基于mixin的组合(mix

第一章 Scala基础篇

目录 一.Scala基础语法 (一) 变量.类型.操作符 1.变量申明 2.字符串 3.数据类型 4.操作符 (二)循环判断 1.块表达式 2.条件表达式 3.循环表达式 (三)方法和函数 1.方法 2.函数 3.方法和函数的区别 4.总结 二.Scala常用数据结构/集合 (一)Scala集合分类和继承体系 1.分类 2.继承体系 (二)数组 (三)元组 (四)List (五)队列 (六)Set (七)Map 一.Scala基础语法 === (一) 变量.类型.操作符 1.变量申明 ●Java

scala函数式编程(二) scala基础语法介绍

上次我们介绍了函数式编程的好处,并使用scala写了一个小小的例子帮助大家理解,从这里开始我将真正开始介绍scala编程的一些内容. 这里会先重点介绍scala的一些语法.当然,这里是假设你有一些java或者python的基础,毕竟大部分人不会将scala当作第一门学习编程的语言. 不过这些语法知识记不住也没关系,本身语法这种东西就应该在使用中被记住.这里写这篇的目的也只是梳理一遍,方便大家对语法有个初步的印象,后面可以随时查询. PS:所使用的版本是scala 2.11.8,那我们开始吧 一.

【C++基础 06】explict关键字

C++提供了关键字explicit,可以阻止不应该允许的经过转换构造函数进行的隐式转换的发生.声明为explicit的构造函数不能在隐式转换中使用. 1.示例 我们先来看一段示例代码: class A { public: A(int v):var(v){};//带一个int型值的构造函数 bool isSame(const A& ref) const {return var == ref.var;}//判等函数 private: int var;//成员变量var }; void main()

Scala基础:面向对象&mdash;&mdash;类

类 (class) 类是对象的模板,通过构造类,能够使用new关键字声明一系列同结构的对象. Scala的一个源文件可以包含多个public类. 声明Person类: class Person{   var name : String = _   val age = 10   private[this] val gender = "male" } 说明: name字段被赋值为"_""_"即占位符.表示name被声明为String.但赋值为&quo

Scala基础

REPL 在Scala中的书籍中会提及REPL,REPL(Read-Eval-Print Loop):这被称为"读取-求值-打印"循环. 不带参数的Scala方法通常不使用圆括号,例如,StringOps类的API显示它有一个distinct方法,不带(),其作用是获取字符串中不重复的字符.调用如下: print("hello".distinct); Scaladoc 阅读Scaladoc的一些小窍门: 如果想使用数值类型,记得看看RichInt.RichDoubl

Python基础06 循环

Python基础06 循环 作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 循环用于重复执行一些程序块.从上一讲的选择结构,我们已经看到了如何用缩进来表示程序块的隶属关系.循环也会用到类似的写法. for循环 for循环需要预先设定好循环的次数(n),然后执行隶属于for的语句n次. 基本构造是 for 元素 in 序列: statement 举例来说,我们编辑一个叫forDemo.py的文件 for a in [3,4.4,