热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

scala继承与组合

http:blog.csdn.netlovehuangjiajuarticledetails47029287主要内容类的继承构造函数执行顺序方法重写匿名类多态与动态绑定组合与继承

http://blog.csdn.net/lovehuangjiaju/article/details/47029287


主要内容


  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")}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

代码

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

等同于下面的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;}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

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")}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

下面这段代码

//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")
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

等同于下面的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");}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

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

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

不得不提的是,如果父类是抽象类,则不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()}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

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() }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

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=0def 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=0def 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)}
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47

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=nullval hadn:Hand=nulll//....
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

继承与组合使用总结:

一 继承

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

二 组合

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


推荐阅读
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • 本文介绍了闭包的定义和运转机制,重点解释了闭包如何能够接触外部函数的作用域中的变量。通过词法作用域的查找规则,闭包可以访问外部函数的作用域。同时还提到了闭包的作用和影响。 ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • 原文地址:https:www.cnblogs.combaoyipSpringBoot_YML.html1.在springboot中,有两种配置文件,一种 ... [详细]
  • Final关键字的含义及用法详解
    本文详细介绍了Java中final关键字的含义和用法。final关键字可以修饰非抽象类、非抽象类成员方法和变量。final类不能被继承,final类中的方法默认是final的。final方法不能被子类的方法覆盖,但可以被继承。final成员变量表示常量,只能被赋值一次,赋值后值不再改变。文章还讨论了final类和final方法的应用场景,以及使用final方法的两个原因:锁定方法防止修改和提高执行效率。 ... [详细]
  • 在Android开发中,使用Picasso库可以实现对网络图片的等比例缩放。本文介绍了使用Picasso库进行图片缩放的方法,并提供了具体的代码实现。通过获取图片的宽高,计算目标宽度和高度,并创建新图实现等比例缩放。 ... [详细]
  • 本文介绍了使用kotlin实现动画效果的方法,包括上下移动、放大缩小、旋转等功能。通过代码示例演示了如何使用ObjectAnimator和AnimatorSet来实现动画效果,并提供了实现抖动效果的代码。同时还介绍了如何使用translationY和translationX来实现上下和左右移动的效果。最后还提供了一个anim_small.xml文件的代码示例,可以用来实现放大缩小的效果。 ... [详细]
  • 向QTextEdit拖放文件的方法及实现步骤
    本文介绍了在使用QTextEdit时如何实现拖放文件的功能,包括相关的方法和实现步骤。通过重写dragEnterEvent和dropEvent函数,并结合QMimeData和QUrl等类,可以轻松实现向QTextEdit拖放文件的功能。详细的代码实现和说明可以参考本文提供的示例代码。 ... [详细]
  • 本文介绍了一个Java猜拳小游戏的代码,通过使用Scanner类获取用户输入的拳的数字,并随机生成计算机的拳,然后判断胜负。该游戏可以选择剪刀、石头、布三种拳,通过比较两者的拳来决定胜负。 ... [详细]
  • 开发笔记:加密&json&StringIO模块&BytesIO模块
    篇首语:本文由编程笔记#小编为大家整理,主要介绍了加密&json&StringIO模块&BytesIO模块相关的知识,希望对你有一定的参考价值。一、加密加密 ... [详细]
  • 本文讨论了如何优化解决hdu 1003 java题目的动态规划方法,通过分析加法规则和最大和的性质,提出了一种优化的思路。具体方法是,当从1加到n为负时,即sum(1,n)sum(n,s),可以继续加法计算。同时,还考虑了两种特殊情况:都是负数的情况和有0的情况。最后,通过使用Scanner类来获取输入数据。 ... [详细]
  • 阿,里,云,物,联网,net,core,客户端,czgl,aliiotclient, ... [详细]
  • 本文介绍了在Java中gt、gtgt、gtgtgt和lt之间的区别。通过解释符号的含义和使用例子,帮助读者理解这些符号在二进制表示和移位操作中的作用。同时,文章还提到了负数的补码表示和移位操作的限制。 ... [详细]
  • Mac OS 升级到11.2.2 Eclipse打不开了,报错Failed to create the Java Virtual Machine
    本文介绍了在Mac OS升级到11.2.2版本后,使用Eclipse打开时出现报错Failed to create the Java Virtual Machine的问题,并提供了解决方法。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
author-avatar
我是你的小pig的美丽家园
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有