Spark学习笔记11面向对象编程

时间:2021-03-16 16:37:31

面向对象编程

 

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的父类