Scala入门到精通——第九节 继承与组合

主要内容

  1. 类的继承
  2. 构造函数执行顺序
  3. 方法重写
  4. 匿名类
  5. 多态与动态绑定
  6. 组合与继承的使用

1 类的继承

下类的代码演示了scala类的继承

//Person类
class Person(name:String,age:Int){

}

//Student继承Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){

}

object demo{
  def main(args: Array[String]): Unit = {

     val student=new Student("john",18,"1024")
  }
}

代码

//Person类
class Person(name:String,age:Int){

}

//Student继承Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){

}

等同于下面的Java代码

//Person类
class Person{
    private String name;
    private int age;
    public Person(String name,int age){
       this.name=name;
       this.age=age;
    }
}

//Student继承Person类
class Student extends Person{
    private String studentNo;
    public Student(string name,int age,String studentNo){
        super(name,age);
        this.sutdentNo=studentNo;
    }
}

2. 构造函数执行顺序

下面的代码演示scala在继承的时候,构造函数的执行顺序

//Person类
class Person(name:String,age:Int){
  println("Constructing Person")
}

//Student继承Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){
  println("Constructing Student")
}

object demo{
  def main(args: Array[String]): Unit = {
     //下面的语句执行时会打印下列内容
     //Constructing Person
     //Constructing Student
     //也就是说,构造Student这前,首先会调用Person的主构造方法
     val student=new Student("john",18,"1024")
  }
}

下面这段代码

//Person类
class Person(name:String,age:Int){
  println("Constructing Person")
}

//Student继承Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){
  println("Constructing Student")
}

等同于下面的java代码

//Person类
class Person{
    private String name;
    private int age;
    public Person(String name,int age){

       this.name=name;
       this.age=age;
       System.out.println("Constructing Person");
    }
}

//Student继承Person类
class Student extends Person{
    private String studentNo;
    public Student(string name,int age,String studentNo){

        super(name,age);
        this.sutdentNo=studentNo;
        System.out.println("Constructing Student");
    }
}

3. 方法重写

方法重写指的是当子类继承父类的时候,从父类继承过来的方法不能满足子类的需要,子类希望有自己的实现,这时需要对父类的方法进行重写,方法重写是实现多态和动态绑定的关键。
scala中的方法重写同java一样,也是利用override关键字标识重写父类的算法。
下面的代码演示了方法重写如何实现

class Person(name:String,age:Int){
  //println("Constructing Person")
  def walk():Unit=println("walk like a normal person")
}

//Student继承Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){
  //println("Constructing Student")
  override def walk():Unit={
    super.walk()//调用父类的walk方法
    println("walk like a elegant swan")//增加了自己的实现
  }
}

object demo{
  def main(args: Array[String]): Unit = {
     val s=new Student("john",18,"1024")
     s.walk()
  }
}

//代码运行输出内容
walk like a normal person
walk like a elegant swan

不得不提的是,如果父类是抽象类,则不override关键字可以不加,这是因为如果继承的父类是抽象类(假设抽象类为AbstractClass,子类为SubClass),在SubClass类中,AbstractClass对应的抽象方法如果没有实现的话,那SubClass也必须定义为抽象类,否则的话必须要有方法的实现,这样的话,加不加override关键字都是可以的。下面是一个实例代码:

//抽象的Person类
abstract class Person(name:String,age:Int){
  def walk():Unit
}

//Student继承抽象Person类
class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){
  //重写抽象类中的walk方法,可以不加override关键字
  def walk():Unit={
    println("walk like a elegant swan")
  }
}

object demo{
  def main(args: Array[String]): Unit = {
     val s=new Student("john",18,"1024")
     s.walk()
  }
}

4. 匿名类

当某个类在程序中只使用一次时,可以将类定义为匿名类,匿名类的定义如下:

//抽象的Person类
abstract class Person(name:String,age:Int){
  def walk():Unit
}

object demo{
  def main(args: Array[String]): Unit = {
     //下面的代码定义了一个匿名类,并且进行了实例化
     //直接new Person("john",18),后面跟的是类的内容
     //我们知道,Person是一个抽象类,它是不能被实例化的
     //这里能够直接new操作是因为我们扩展了Person类,只不
     //过这个类是匿名的,只能使用一次而已
     val s=new Person("john",18){
       override def walk()={
         println("Walk like a normal Person")
       }
     }
     s.walk()
  }
}

5 多态与动态绑定

“多态”(Polymorphic)也叫“动态绑定”(Dynamic Binding)、“迟绑定”(Late Binding),指“在执行期间(而非编译期间)判断所引用对象的实际类型,根据其实际类型调用其相应的方法。”即指子类的引用可以赋给父类,程序在运行时根据实际类型调用对应的方法
下面的代码演示了scala中的多态与动态绑定:

//抽象Person类
abstract class Person(var name:String,var age:Int){

  def walk():Unit
  //talkTo方法,参数为Person类型
  def talkTo(p:Person):Unit
}

class Student(name:String,age:Int) extends Person(name,age){
  private var studentNo:Int=0
  def walk()=println("walk like a elegant swan")
  //重写父类的talkTo方法
  def talkTo(p:Person)={
    println("talkTo() method in Student")
    println(this.name+" is talking to "+p.name)
  }
}

class Teacher(name:String,age:Int) extends Person(name,age){
  private var teacherNo:Int=0

  def walk()=println("walk like a elegant swan")

   //重写父类的talkTo方法
  def talkTo(p:Person)={
    println("talkTo() method in Teacher")
    println(this.name+" is talking to "+p.name)
  }
}

object demo{
  def main(args: Array[String]): Unit = {

     //下面的两行代码演示了多态的使用
     //Person类的引用可以指向Person类的任何子类
     val p1:Person=new Teacher("albert",38)
     val p2:Person=new Student("john",38)

     //下面的两行代码演示了动态绑定
     //talkTo方法参数类型为Person类型
     //p1.talkTo(p2)传入的实际类型是Student
     //p2.talkTo(p1)传入的实际类型是Teacher
     //程序会根据实际类型调用对应的不同子类中的talkTo()方法
     p1.talkTo(p2)
     p2.talkTo(p1)
  }
}

6. 组合与继承的使用

继承可以重用父类的代码,从而简化程序设计,继承是is-a的关系,apple is a kind of fruit(苹果是一种水果)。还有一种代码重用的方式是组合,组合是has-a的关系(one person has a head)。继承在前面已经讲了,这边只给出组合的使用代码:

class Head
class Body
class Hand
//....

//Person类
abstract class Person(var name:String,var age:Int){
  //各类的实例作为该类对象的一部分,通过各类的实例方法实现代码重用
  val head:Head=null
  val body:Body=null
  val hadn:Hand=nulll
  //....
}

继承与组合使用总结:

一 继承

  继承是Is a 的关系,比如说Student继承Person,则说明Student is a Person。继承的优点是子类可以重写父类的方法来方便地实现对父类的扩展。
  继承的缺点有以下几点:
  1 父类的内部细节对子类是可见的。
  2 子类从父类继承的方法在编译时就确定下来了,所以无法在运行期间改变从父类继承的方法的行为。
3 如果对父类的方法做了修改的话(比如增加了一个参数),则子类的方法必须做出相应的修改。所以说子类与父类是一种高耦合,违背了面向对象思想。

二 组合

  组合也就是设计类的时候把要组合的类的对象加入到该类中作为自己的成员变量。组合的优点:
   1 当前对象只能通过所包含的那个对象去调用其方法,所以所包含的对象的内部细节对当前对象时不可见的。
  2 当前对象与包含的对象是一个低耦合关系,如果修改包含对象的类中代码不需要修改当前对象类的代码。
  3 当前对象可以在运行时动态的绑定所包含的对象。可以通过set方法给所包含对象赋值。
  组合的缺点:
  1 容易产生过多的对象。
  2 为了能组合多个对象,必须仔细对接口进行定义。
由此可见,组合比继承更具灵活性和稳定性,所以在设计的时候优先使用组合。只有当下列条件满足时才考虑使用继承:
1 子类是一种特殊的类型,而不只是父类的一个角色
2 子类的实例不需要变成另一个类的对象
3 子类扩展,而不是覆盖或者使父类的功能失效

添加公众微信号,可以了解更多最新Spark、Scala相关技术资讯

时间: 2024-11-30 07:09:02

Scala入门到精通——第九节 继承与组合的相关文章

Scala入门到精通—— 第二节Scala基本类型及操作、程序控制结构

本节主要内容 Scala基本类型 基本类型操作 Scala程序控制结构 Scala基本类型 Scala中的基本数据类型如下图: (来源:Programming in Scala) 从上表中可以看出,Scala的基本数据类型与Java中的基本数据类型是一一对应的,不同的是Scala的基本数据类型头字母必须大写,本节以Int.Long.String.Char.Double及Float类型为例介绍Scala的基本类型定义 整数类型变量定义: //16进制定义法 scala> val x=0x29 x:

Scala入门到精通——第一节 Scala语言初步

本节主要内容 Scala简介 为什么要学习Scala Scala语言初步 1. Scala简介 Scala(Scala Language的简称)语言是一种能够运行于JVM和.Net平台之上的通用编程语言,既可用于大规模应用程序开发,也可用于脚本编程,它由由Martin Odersk于2001开发,2004年开始程序运行在JVM与.Net平台之上,由于其简洁.优雅.类型安全的编程模式而受到关注. Scala的创建者--Martin Odersk 在Scala的创建之初,并没有怎么引起重视,随着Ap

Scala入门到精通——第三十节 Scala脚本编程与结束语

本节主要内容 REPL命令行高级使用 使用Scala进行Linux脚本编程 结束语 1. REPL命令行高级使用 在使用REPL命令行时,有时候我们需要粘贴的代码比较大,而普通的粘贴可能会些一些问题,比如中文粘贴会出现乱码.多行代码粘贴时会出错,此时需要用到REPL的高级功能.在日常开发过程中,我们粘贴多行代码的时候会遇到下列问题: //本意是要粘贴下面两行代码 class Person(val name:String,val age:Int) val p=new Person("摇摆少年梦&q

《面向对象设计实践指南:Ruby语言描述》—第8章 8.5节继承和组合的抉择

8.5 继承和组合的抉择 面向对象设计实践指南:Ruby语言描述 请记住,经典继承是一种代码编排技术.行为分散在对象里面,而对象被组织成类关系,以便消息可以自动委托调用正确的行为.这个问题可以按这样一种方式来考虑:就某个层次结构里的对象编排成本而言,消息委托是免费的. 组合是将这些"利与弊"颠倒过来的另一种选择.在组合里,对象之间的关系并没有体现在类层次结构里.相反,对象独立存在.其结果就是,必须明确地了解消息,并将它们委托给另一个对象.组合支持对象之间的结构独立性,其代价是需要显式地

Scala入门到精通——第七节:类和对象(二)

本节主要内容 单例对象 伴生对象与伴生类 apply方法 应用程序对象 抽象类 单例对象 在某些应用场景下,我们可能不需要创建对象,而是想直接调用方法,但是Scala语言并不支持静态成员,Scala通过单例对象来解决该问题.单例对象的创建方式如下: object Student { private var studentNo:Int=0; def uniqueStudentNo()={ studentNo+=1 studentNo } def main(args: Array[String]):

Scala入门到精通——第十四节 Case Class与模式匹配(一)

本节主要内容 模式匹配入门 Case Class简介 Case Class进阶 1. 模式匹配入门 在java语言中存在switch语句,例如: //下面的代码演示了java中switch语句的使用 public class SwitchDemo { public static void main(String[] args) { for(int i = 0; i < 100; i++) { switch (i) { case 10:System.out.println("10"

Scala入门到精通——第二十七节 Scala操纵XML

本节主要内容 XML 字面量 XML内容提取 XML对象序列化及反序列化 XML文件读取与保存 XML模式匹配 1. XML 字面量 XML是一种非常重要的半结构化数据表示方式,目前大量的应用依赖于XML,这些应用或利用XML作为数据交换格式,或利用XML进行文件配置等.像JAVA.C++及其它流行的程序开发语言都是依赖于第三方库来实现XML的操作,例如JAVA经常通过JDOM,DOM4J等XML处理工具进行XML的操纵,但Scala提供了对XML的原生支持,通过scala.xml._包下的类或

Scala入门到精通——第十一节 Trait进阶

本节主要内容 trait构造顺序 trait与类的比较 提前定义与懒加载 trait扩展类 self type 1 trait构造顺序 在前一讲当中我们提到,对于不存在具体实现及字段的trait,它最终生成的字节码文件反编译后是等同于java中的接口,而对于存在具体实现及字段的trait,其字节码文件反编译后得到的java中的抽象类,它有着scala语言自己的实现方式.因此,对于trait它也有自己的构造器,trait的构造器由字段的初始化和其它trait体中的语句构成,下面是其代码演示: pa

Scala入门到精通——第二十节 类型参数(二)

本节主要内容 Ordering与Ordered特质 上下文界定(Context Bound) 多重界定 类型约束 1. Ordering与Ordered特质 在介绍上下文界定之前,我们对scala中的Ordering与Ordered之间的关联与区别进行讲解,先看Ordering.Ordered的类继承层次体系: 通过上面两个图可以看到,Ordering混入了java中的Comparator接口,而Ordered混入了java的Comparable接口,我们知道java中的Comparator是一