面向对象编程
11.1 object类
11.1.1定义一个简单的类
11.1.2 field的getter与setter
定义类包含,定义类的field及方法。其格式如下
class ClassName{ // 其中类名首字母要大写
private var name = "Hys" // private修试符说明此变量只对本类有效
def sayHello(){ print("Hello," + name)
def getName = name // 获取name 的值
}
创建类的对象,并调用其方法
val field_name = new ClassName // 创建类对象
field_name.sayHello() // 调用类方法
print(field_name.getName()) // 调用类成员
11.1.3 构造函数-constructor
11.1.4 内部类
11.2 对象
11.3 继承
继承的主要有点:可以减少代码量
11.3.1 关键字extends
*父类中用final修饰的field和method是无法被子类继承的
示例代码:
class Person {
private var name = "George"
def getName = name
}
class Student extends Person {
private var score = "A"
def getScore = score
}
11.3.2 子类覆盖父类field和method
1.override关键字
使用此关键字覆盖可以帮助发现代码里的错误
2.父类方法被覆盖之后还可以使用super调用父类方法
示例代码:
class Person{
private var name = "George"
def getName = name
}
class teacher extends Person{
private var age = 20
def getAge = age
override def getName = "Hello " + super.getName
}
3. override field
示例代码:
class Person{
val name:String = "Hys"
def age:Int = 20
}
class Teacher extends Person{
override val name:String = "George"
override val age:Int = 30
}
4.isInstanceOf 和 asInstanceOf
isInstanceOf :判断指定对象是否为指定类或其子类的对象,如果对象是null则一定返回false
asInstanceOf:将指定对象转换为指定类型
示例代码:
class Person
class Teacher extends Person
val p:Person = new Teacher
val t:Teacher = null
if(p.isInstanceOf[Teacher]) t = p.asInstanceOf[Teacher]
5.getClass 和 classOf[类]
p.getClass 可以获取对象被实例化的类型
classOf[类] 可以获取精确的类
示例代码:
p.getClass == classOf[Person] 判断p是否是被实例化为Person类型
p.getClass == classOf[Teacher]
6. 模式匹配进行类型判断
*判断对象是否和该类及其子类的对象
p match{
case per:Person => println("it's Person's object")
case _ => println("Unknown type")
}
7.关键字protected
*父类中使用protected 修试的field 和 method在子类中直接就可以访问。
*当使用protected[this]时只能在"子类 当前对象"中访问父类的,其它对象不可以,包括同类对象。
代码示例:
class Person{
protected var name:String = "Hys"
}
class Teacher extends Person{
def sayHello() = {println("Hello " + name)}
}
val t = new Teacher
t.sayHello
8. 调用父类的构造函数constructor
*只能在子类的主constructor中调用父类的constructor;原因是辅构造函数只能调用本类的主构造函数或者辅构造函数
* 父类中接收的参数,子类中就不要用任何val 或者var 来修饰,否在认为是要覆盖父类的field
示例代码:
class Person(val name:String, val age:Int)
class Teacher(name:String, age:Int, var score:Double) extends Person(name,age){
def this(name:String){
this(name,0,0)
}
def this(age:Int){
this("Hys",age,0)
}
}
8.调用父类的constructor
* 每个类的辅助构造函数(constructor)只能调用本类的辅助constructor或者主constructor,所以要调用父类构造函数必须使用子类的主构造函数。
*如果是父类中接收的参数,子类接收时就不要用var或者val 来修饰了,否则会认位是覆盖父类的field 。
示例代码:
Class Person(val name:String, val age:Int){
Println("Person's name is " + name)
Println("Person's age is " + age)
}
Class Teacher(name:String, age:Int, var score:Double) extends Person(name, age){
def this(name:String){
this(name:String)
}
def this(age:Int){
this("Hys ",age,0)
}
Println(name + " " + age + " " + score)
}
val t = new Teacher("George", 20, 100)
Person's name is George
Person's age is 20
George 20 100.0
9.匿名内部类
*匿名子类:定义的没有名字的子类,同时直接创建其对象,然后将对象的引用赋予一个变量。然后匿名子类的对象也可以传给其它函数。
示例代码:
class Person(protected val name:String){
def sayHello = "Hello, I'm " + name
}
val p = new Person("Hys") {
override def sayHello = "Nice to meet you " + name} //匿名子类
def greeting(p:person{def sayHello:String}){ //把匿名子类当成参数传给函数
println(p.sayHello)
}
greeting(p) //调用匿名子类实例
10.抽象类
*抽象方法:定义时只有方法名和方法类型的方法。
*抽象类:包含抽象方法的类就是抽象类,即只要类中有一个抽象方法此类就为抽象类。
*抽象类必须用abstract关键词修饰。
*抽象类不可以被实例化。
*在子类中覆盖抽象类的方法时不需要用override关键字。
代码示例:
abstract class Person(){ //定义抽象类
def sayHello:String
}
class Teacher(name:String) extends Person{ //继承抽象类
def sayHello:String = {println("Hello" + name ); name} // 覆盖父类方法
}
val t = new Teacher("Hys")
t.sayHello
11.抽象field
*抽象field:定义field时只给出类型没有给出初值,这样的field就是抽象field。
*Scala会根据自己的规则为var或者val类型的field生成对应的getter和setter方法,但是父类中是没有field的,就父类中的抽象field不占内存。
*子类必须覆盖父类的抽象field。
*子类覆盖父类的抽象field不需要override关键字。
示例代码(子类不覆盖父类抽象field报错):
Abstract class Person{ //定义抽象类
Val name:String
}
class Teacher extends Person{} //子类不重写代码,报错
(子类正常继承父类)
class Teacher extends Person{
val name:String = "Hys" // 覆盖父类抽象方法
}
(子类把父类的抽象field继承为抽象field操作)
class Teacher extends Person{ val name:String } // 把父类抽象方法继承为抽象方法,如果不用abstract修饰子类会有报错
abstract class Teacher extends Person{ val name:String} //正确的把父类抽象方法继承为抽象方法
11.4 Trait
11.4.1基础知识
1.将trait作为接口使用
*类使用关键字extends继承
*与Java中的接口一样
*抽象方法不需要overrid管家你
*Scala不支持对类进行多继承,但可以多继承trait,使用with关键字
代码示例:
trait HelloTrait{
def sayHello(name:String)
}
trait MakeFriendsTrait{
def makeFriends(p:Person)
}
class Person(val name:String) extends HelloTrait with MakeFriendsTrait with Cloneable with Serializable{
def sayHello(name:String) = println("Hello " + name)
def makeFriends(p:Person) = println("Hello, my name is " + name + " your name is " + p.name)
}
2.在trait中定义具体方法
*就像类中定义方法一样
*不同之处在子类中调用是直接使用方法名就可以
trait computer{
def playVideo()={println("Play video")}
}
class Person extends computer{
playVideo()
def play()={playVideo()}
}
val p = new Person
p.playVideo
3.在trait中定义具体字段
*与类继承不同,trait定义的具体字段直接添加到了继承它的类中
trait Person{
val eyeNum:Int = 2
}
class Teacher(val name:String, val age:Int) extends Person{
println("Hello "+ name + ", you have " + eysNum + "eyes")
}
4.在trait中定义抽象字段
*trait中可以定义抽象字段,同时trait中的具体方法可以基于抽象字段来写,只不过继承trait的类必须覆盖抽象的field,提供具体的值
trait SayHello {
val name:String
def sayHello()={"Hello " + name}
}
class Person extends SayHello{
val name:String = "Hys" //覆盖trait中抽象字段
def makeFriends(p:Person){
sayHello()
println(name + ", nice to meet you")
}
}
11.4.2高级知识
1.为实例对象混入trait
*只有本对象可以调用
trait Loger{
def log(msg:String){print("loger trait")}
def logTrait(){println("loger trait")}
}
trait MyLoger extends Loger{
override def log(msg:String){println("log:" + msg)}
}
class Person(val name:String) extends Loger{
def sayHello{println("Hi,I'm " + name );log("sayHello is invoked!")}
}
val p2 = new Person("George") with MyLoger //动态混入trait
val p1 = new Person("Hys")
scala> p2.logTrait()
trait
scala> p1.log("")
loger trait
2.trait调用链
*继承同一个trait的多个trait,在具有相同method的最后都执行super.method,就可以从右向左依次执行每个被继承的多个trait中相同的方法,从而实现调用链。
代码示例:
trait Loger{
def vs(){}
def kk(){}
}
trait PersonReady extends Loger{
override def vs(){
println("I am ready")
super.vs() //执行此方法
}
}
trait PersonGo extends Loger{
override def vs(){
println("Please go!")
super.vs()
}
}
trait PersonEnd extends Loger{
override def vs(){
println("To be end!")
super.vs()
}
}
class PersonVs extends PersonEnd with PersonGo with PersonReady{
def aURD(name:String){
println("Are you ready")
vs() //执行调用链
}
}
3.在trait中覆盖抽象方法
*当子trait调用super.method_name 时要要给子trait的方法加上abstract override修饰
示例代码1(无super.method_name调用):
trait Logger{
def log(msg:String)
}
trait Mylogger extends Logger{
override def log(msg:String){}
}
示例代码2(有super.method_name调用):
trait Logger{
def log(msg:String)
}
trait Mylogger extends Logger{
abstract override def log(msg:String){super.log("kk")} // 当调用super.method_name时要用abstract修饰
}
4.混合使用trait的具体方法和抽象方法
*可以让trait中具体方法依赖于抽象方法,而抽象方法则放到继承trait的类中去实现,就好像是一个模板
trait Valid{
def getName:String //在trait中定义抽象方法
def valid:Boolean={ //在trait中定义具体方法
getName == "Hys"
}
}
class Person(val name:String) extends Valid{
println(valid) //此语句需要执行的函数及次序是construceto->getName->vaild
def getName = {println("Get the name.")
name
}
}
5.trait的构造机制
*trait中不包含在任何方法中的代码就是trait的构造代码
*构造代码执行优先级 父类构造函数->多个trait从左到右依次执行->父trait的构造代码->子类的构造函数
示例代码:
class Person{print("Person's constructor")}
trait Logger{println("\n Logger constructor")}
trait Logger{println("\n Logger constructor")}
trait TimeLogger extends Logger{println("TimeLogger")}
class Teacher extends Person with TimeLogger with MyLogger{println("Tescher class")}
实例化演示:
scala> val t = new Teacher
Person's constructor
Logger constructor
TimeLogger
Mylogger constructor
Tescher class
6.trait字段的初始化
*trait不可以接收带参数的构造函数,如果想使用trait初始化field,可以使用Scala的提前定义特性
示例代码:
trait SayHello{
val msg:String //需要初始化的字段
println(msg.toString) // 对初始化字段的调用
}
class Person
val p = new Person with SayHello //报错
val p = new {val msg:String = "Hys" //提前定义
} Person with SayHello
或者
class Person extends { val msg:String = "Hys" //提前定义
} with SayHello
还有办法就是使用lazy value
*如果不用lazy仍然会报异常
trait SayHello {
lazy val msg:String = null
println(msg:toString)
}
class Person extends SayHello //继承的时候没有用lazy,实例化时有异常发生
val p = new Person //有异常跳出
class Person extends SayHello{ override lazy val msg:String = "George"} //使用lazy覆盖该field,实例化时正常
val p = new Person
7.让trait继承类
*trait也可以继承自class,此时class就回成为所有继承该trait的类的父类
示例代码:
class Hys { println("class Hys")}
trait George extends Hys {println("trait George")} //trait 继承类
class Person extends George{println("class Person")} //之类继承继承了类的trait,此时trait继承的类相当于继承了该trait的父类。
scala> val p = new Person
class Hys
trait George
class Person
由构造函数执行内容和顺序可知Hys类是Person的父类