实验六 Scala的继承和特质
- 一、实验目的
- 二、实验内容
- 三、实验要求
- 四、实验步骤
- 1.Scala中类的继承
- 2.方法重写
- 3.抽象类的继承和方法重写
- 4.Scala中匿名类的使用
- 5.检查和转换
- 6.组合
- 7.多态
- 8创建Scala特质
- 9混入特质以及特质和接口的区别
- 10.Trait的构造顺序
- 11.Trait扩展类
- 五、思考题
一、实验目的
1、掌握Scala类的继承。
2、掌握Scala中的多态。
3、掌握Scala中的特质的构造顺序。
4、掌握Scala中的特质如何扩展类。
二、实验内容
该实验使用Scala的API学习类的继承,熟悉继承的相关概念及作用,熟悉多态的概念,掌握Scala基础编程,了解特质与Java接口的异同,理解特质的构造顺序,并利用特质实现扩展类。
三、实验要求
? 1、JDK1.8环境
? 2、Scala-2.12.4(Scala-2.11.12)
? 3、本实验基于Linux,可根据自身情况选择平台进行实验。
4、根据实验手册的内容,按步骤完成练习。
四、实验步骤
1.Scala中类的继承
1.1打开Scala IDE(IDEA community),创建Scala Project Test3,如图:

1.2创建包org.zkpk.scala

1.3在包org.zkpk.scala下创建Object Demo01.scala


1.4在object Demo01外创建父类Animal类,构造器参数为空,且输出字符串“Animal”
class Animal{
println("Animal")
}
1.5在object Demo01外创建子类Tiger类,继承Animal类,Tiger类构造参数为空,且输出字符串“Tiger”
class Tiger extends Animal{
println("Tiger")
}
1.6在object Demo01中定义main方法,创建子类对象
object Demo01 {
def main(args: Array[String]): Unit = {
val tiger=new Tiger
}
}
1.7整体代码如下:
package base_test.test6
class Animal{
println("Animal")
}
class Tiger extends Animal{
println("Tiger")
}
object Demo01 {
def main(args: Array[String]): Unit = {
val tiger=new Tiger
}
}
1.8点击右键,依次选择Run as--->Scala Application点击运行,查看结果

2.方法重写
2.1在org.zkpk.scala下创建Object Demo02.scala
2.2在object Demo02外创建父类Company,复写toString方法,即在调用Company对象的toString方法时会返回字符串“Company toString”:
class Company {
override def toString() = {
"Company toString"
}
}
2.3在object Demo02外创建子类Department继承Company,复写继承的toString方法,即在调用Department对象的toString方法时会返回字符串“Department toString”:
class Department extends Company{
override def toString(): String = {
"Department toString"
}
}
2.4在object Demo02中定义main方法,创建子类对象,打印输出dp对象的toString方法
object Demo02 {
def main(args: Array[String]): Unit = {
val dp=new Department
println(dp.toString())
}
}
2.5整体代码如下:
package base_test.test6
class Company {
override def toString() = {
"Company toString"
}
}
class Department extends Company{
override def toString(): String = {
"Department toString"
}
}
object Demo02 {
def main(args: Array[String]): Unit = {
val dp=new Department
println(dp.toString())
}
}
2.6点击右键,依次选择Run as--->Scala Application运行程序,查看结果

3.抽象类的继承和方法重写
3.1在org.zkpk.scala下创建Object Demo03.scala
3.2在object Demo03外创建抽象父类Animal1,其中包含两个抽象方法shout()和run():
abstract class Animal1 {
def shout()
def run()
}
3.3在object Demo03外创建非抽象类Tiger1继承自Animal1,实现所有抽象方法:
class Tiger1 extends Animal1{
def shout()={
println("Tiger shout")
}
override def run(): Unit = {
println("Tiger run")
}
}
3.4创建抽象类Wolf继承抽象父类Animal1,不需要实现具体方法
abstract class Wolf extends Animal1{
}
3.5在object Demo03中定义main方法,创建Tiger1实例对象,调用tiger对象的run()方法和shout()方法:
object Demo03 {
def main(args: Array[String]): Unit = {
val tiger1=new Tiger1
tiger1.run()
tiger1.shout()
}
}
3.6整体代码如下:
package base_test.test6
abstract class Animal1 {
def shout()
def run()
}
abstract class Wolf extends Animal1{
}
class Tiger1 extends Animal1{
def shout()={
println("Tiger shout")
}
override def run(): Unit = {
println("Tiger run")
}
}
object Demo03 {
def main(args: Array[String]): Unit = {
val tiger1=new Tiger1
tiger1.run()
tiger1.shout()
}
}
3.7点击右键,依次选择Run as--->Scala Application运行程序,查看结果

4.Scala中匿名类的使用
4.1在org.zkpk.scala下创建Object Demo04.scala)
4.2在object Demo04外创建抽象父类Animal2,其中包含两个抽象方法shout()和run()
abstract class Animal2{
def shout()
def run()
}
4.3在object Demo04中创建抽象类Wolf2继承自抽象类Animal2,不复写父类中的任何方法
abstract class Wolf2 extends Animal2{
}
4.4在object Demo04中创建main方法,main方法中创建Wolf对象的匿名类,匿名类复写了Wolf对象的shout方法和run方法:
object Demo04 {
def main(args: Array[String]): Unit = {
val wolf=new Wolf {// 创建匿名类,匿名类只能使用一次
def shout(){println("Wolf shout")}
def run(){println("Wolf run")}
}
wolf.run()
wolf.shout()
}
}
4.5整体代码如下:
package base_test.test6
abstract class Animal2{
def shout()
def run()
}
abstract class Wolf2 extends Animal2{
}
object Demo04 {
def main(args: Array[String]): Unit = {
val wolf=new Wolf {// 创建匿名类,匿名类只能使用一次
def shout(){println("Wolf shout")}
def run(){println("Wolf run")}
}
wolf.run()
wolf.shout()
}
}
4.6点击右键,依次选择Run as--->Scala Application点击运行,查看结果

5.检查和转换
5.1在org.zkpk.scala下创建Object Demo05.scala
5.2在object Demo05中创建main方法,代码如下:
package base_test.test6
object Demo05 {
def main(args: Array[String]): Unit = {
val department=new Department
// 判断对象的类型是否给定的Department
if(department.isInstanceOf[Department]){
println("department对象的类型是Department")
}
if(department.isInstanceOf[Company]){
println("department对象的类型是Company")
// 类型转换一下
val company=department.asInstanceOf[Company]
println(company.toString())
}
//getClass classOf[]
if(department.getClass == classOf[Department]){
println("department对象的类型是Department")
}
}
}
5.3点击右键,依次选择Run as--->Scala Application运行程序,查看结果
department对象的类型是Department
department对象的类型是Company
Department toString
department对象的类型是Department
6.组合
6.1在org.zkpk.scala下创建Object Demo06.scala
6.2在object Demo06外创建三个基本类:类Head包含一个think()方法,输出字符串“think”;类Body包含一个sleep()方法,输出字符串“sleep”;类Feet包含一个walk()方法,输出字符串“walk”

6.3在object Demo06外创建实例类Cat,类Cat包含三个常量对象,分别是Head、Body、Feet,同时包含一个walk()方法,作用是调用Feet对象的walk方法

6.4在object Demo06中创建Cat对象,调用Cat对象的walk方法,实际调用Feet类的方法,简称组合

6.5整体代码如下:
package base_test.test6
// 组合方式
class Head{
def think()=println("think")
}
class Body{
def sleep()={println("sleep")}
}
class Feet{
def walk()={println("walk")}
}
//组合的形式
class Cat{
val head:Head=new Head
val body:Body=new Body
val feet=new Feet
def walk(): Unit ={
feet.walk()
}
}
object Demo06 {
def main(args: Array[String]): Unit = {
val cat=new Cat
cat.walk()
}
}
6.6点击右键,依次选择Run as--->Scala Application运行程序,结果如下
walk
7.多态
7.1在org.zkpk.scala下创建Object Demo07.scala
7.2在object Demo07外创建抽象类Person,Person的构造器参数为:String类型的name,Int类型的age,Person类包含两个抽象方法,分别是:walk()和talkTo()

7.3在object Demo07外创建类Student继承Person类,构造器包含两个参数name:String和age:Int,Student复写父类中的walk方法,输出字符串语句,并复写父类中的talkTo方法,输出字符串语句和参数对象Person的name

7.4创建类Teacher继承Person,构造器包含两个参数name:String和age:Int,Teacher复写父类中的walk方法,输出字符串语句,并复写父类中的talkTo方法,输出字符串语句和参数对象Person的name,同时创建main方法,创建父类型指向子类对象:Person类型的Teacher和父类Person类型的Student对象,代码如下:
package base_test.test6
// 抽象person类
abstract class Person(var name:String,var age:Int){
def walk():Unit
//talkTo方法,参数是Persion类型
def talkTo(p:Person):Unit
}
class Student(name:String, age:Int) extends Person(name, age){
def walk()={println("walk like a alegant swan")}
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){
def walk()={println("walk like a alegant swan")}
def talkTo(p:Person)={
println("talkTo() method in Teacher")
println(this.name+" is talking to "+p.name)
}
}
object Demo07 {
def main(args: Array[String]): Unit = {
//下面两行代码演示了多态的使用
//Person类的引用可以指向Person类的任何子类
val p1:Person=new Teacher("albert", 38)
val p2:Person=new Student("john", 28)
//下边的两行代码演示了动态绑定
//p1.talkTo(p2)传入的实际类型是Student
//p2.talkTo(p2)传入的实际类型是Teacher
//程序会根据实际类型调用对应的不同子类的talkto()方法
p1.talkTo(p2)
p2.talkTo(p1)
}
}
7.9依次选择Run as--->Scala Application点击运行,查看结果
talkTo() method in Teacher
albert is talking to john
talkTo() method in Student
john is talking to albert
8创建Scala特质
8.1在当前录下创建文件DAO.scala,代码如下:
package base_test.test6
trait DAO{
def delete(id:String):Boolean
def add(o:Any):Boolean
def update(o:Any):Int
def query(id:String):List[Any]
}
object TraitDemo01 {
}
8.2利用javap反编译,查看结果
scalac DAO.scala
javap –private DAO

9混入特质以及特质和接口的区别
9.1打开Scala IDE,创建Scala工程Test5
9.2创建包org.zkpk.scala
9.3在包org.zkpk.scala下创建Object Demo01.scala
9.4在object Demo01外创建特质Mytrait,定义特质中的方法和字段:delete方法,没有方法体,为抽象方法; add方法,没有方法体,为抽象方法;update方法,没有方法体,为抽象方法; connectDB方法,包含具体方法体;抽象字段sessionNum以及具体字段port,代码如下:
trait MyTrait{
def delete(id:String):Boolean
def add(o:Any):Boolean
def update(o:Any):Int
//trait可以带有具体实现的方法
def connectDB()={println("connect db")}
//可以带有具体字段
val port:Int=9999
//可以带有抽象字段
val sessionNum:Int
}
9.5创建实例类混入特质,实现特质中所有抽象方法,实现方法时,要根据方法的返回类型来定义:
class TraitImpl extends MyTrait{
def delete(id:String):Boolean=true
def add(o:Any):Boolean=true
def update(o:Any):Int=1
val sessionNum:Int=1
}
9.6在object Demo01中定义main方法,在main方法中,创建实例类对象,并调用对象的connectDB、add、delete、update方法和sessionNum属性打印输出,代码如下:
object TraitDemo {
def main(args: Array[String]): Unit = {
val tl=new TraitImpl
tl.connectDB()
println(tl.add())
println(tl.delete(""))
println(tl.update())
println(tl.sessionNum)
}
}
9.7整体代码如下:
package base_test.test6
trait MyTrait{
def delete(id:String):Boolean
def add(o:Any):Boolean
def update(o:Any):Int
//trait可以带有具体实现的方法
def connectDB()={println("connect db")}
//可以带有具体字段
val port:Int=9999
//可以带有抽象字段
val sessionNum:Int
}
class TraitImpl extends MyTrait{
def delete(id:String):Boolean=true
def add(o:Any):Boolean=true
def update(o:Any):Int=1
val sessionNum:Int=1
}
object TraitDemo {
def main(args: Array[String]): Unit = {
val tl=new TraitImpl
tl.connectDB()
println(tl.add())
println(tl.delete(""))
println(tl.update())
println(tl.sessionNum)
}
}
9.8点击右键,依次选择Run as---->Scala Application运行程序,查看结果
connect db
true
true
1
1
10.Trait的构造顺序
10.1在包org.zkpk.scala下创建Object Demo02.scala
10.2在object Demo02外创建父类和特质:
package base_test.test6
class FatherClass{
println("FatherClass constructor")
}
trait Trait1 extends FatherClass{
println("Trait1 constructor")
}
trait Trait2 extends Trait1{
println("Trait2 constructor")
}
trait Trait3 extends Trait1{
println("Trait3 constructor")
}
class TraitImpl1 extends Trait2 with Trait3{
println("TraitImpl1 constructor")
}
object TraitDemo01 {
}
创建类FatherClass,构造器参数为空,输出字符串语句“FatherClass constructor”,创建特质Trait1继承类FatherClass,输出字符串语句“Trait1 constructor”,创建特质Trait2混入特质Trait1,输出字符串语句“Trait2 constructor”,创建特质Trait3混入特质Trait2,输出字符串语句“Trait3 constructor”,创建类TraitImpli混入特质Trait2和特质Trait3,构造器中输出字符语句“TraitImpli constructor”:
10.3在object Demo02中创建main方法,在main方法中创建TraitImpli对象,观察该对象的构造顺序:
object TraitDemo01 {
def main(args: Array[String]): Unit = {
new TraitImpl1
}
}
10.4整体代码如下:
package base_test.test6
class FatherClass{
println("FatherClass constructor")
}
trait Trait1 extends FatherClass{
println("Trait1 constructor")
}
trait Trait2 extends Trait1{
println("Trait2 constructor")
}
trait Trait3 extends Trait1{
println("Trait3 constructor")
}
class TraitImpl1 extends Trait2 with Trait3{
println("TraitImpl1 constructor")
}
object TraitDemo001 {
def main(args: Array[String]): Unit = {
new TraitImpl1
}
}
10.5点击右键,选择Run as---->Scala Application运行程序,查看结果
FatherClass constructor
Trait1 constructor
Trait2 constructor
Trait3 constructor
TraitImpl1 constructor
11.Trait扩展类
11.1在包org.zkpk.scala下创建Object Demo03.scala
11.2在object Demo03外创建特质Logger,内容为空;
trait Logger{}
trait ExceptionLogger extends Exception with Logger{}
class ExceptionClass extends ExceptionLogger{
//那么ExceptionLogger的父类Exception自动成为ExceptionClass的父类
def test()={
//getmessage是Exception类中的一个方法
println(getMessage)
}
}
创建特质ExceptionLogger继承Exception类,并混入特质Logger;创建类ExceptionClass混入特质ExceptionLogger,那么Exception自动成为特质ExceptionClass的父类:
11.5在object Demo03外创建类ExceptionClass1继承IOException并混入ExceptionLogger特质,类中定义方法test方法,调用println方法输出Exception类的getMessage方法返回的参数:

11.8 IOException是Exception子类,所以Exception是类ExceptionClass1的顶级父类,在object Demo03中定义main方法,main方法为空:
package base_test.test6
import java.io.IOException
trait Logger{}
trait ExceptionLogger extends Exception with Logger{}
class ExceptionClass extends ExceptionLogger{
//那么ExceptionLogger的父类Exception自动成为ExceptionClass的父类
def test()={
//getmessage是Exception类中的一个方法
println(getMessage)
}
}
class ExceptionClass1 extends IOException with ExceptionLogger{
// IOExcepttion是Exception的子类,所以Excption是ExceptionClass1的顶级父类
def test()={
//getmessage是Exception类中的一个方法
println(getMessage)
}
}
object TraitDemo03 {
def main(args: Array[String]): Unit = {
}
}
11.8点击右键,依次选择Run as---->Scala Application运行,运行无报错,即为正确。
无报错
11.9典型错误详解,部分代码如下:

五、思考题
1.下面的脚本定义了一个父类C和一个特质T,T继承自C,然后定义了一个类C1混入特质T,最后实例化一个C1的变量,请检查脚本中的错误,并尝试修改以得到期望的结果。
class C(val name:String)
trait T extends C{ def fly()}
class C1(val name:String) with T{
? def fly(){ println(“I can fly.”)}
}
val t = new C1(“Scala”)
println(t.name) //期望输出Scala
t.fly //期望输出I can fly.
错误原因
1、无论是继承abstract class或者混入trait,对于一个要实现的类来说,必须先用extends,剩下的用with,否则编译的时候就会出错
正确的代码
class C(val name:String)
trait T extends C{
def fly()
}
class C1(name:String) extends C(name) with T{
override def fly(): Unit = {
println("I can fly.")
}
}
object A{
def main(args: Array[String]): Unit = {
val t = new C1("Scala")
println(t.name) //期望输出Scala
t.fly //期望输出I can fly.
}
}