• Spark基础-scala学习(二、面向对象)


    面向对象编程之类

    //定义一个简单的类
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    //类默认public的
    class HelloWorld{
      private var name = "leo"
      def sayHello(){print("Hello,"+name)}
      def getName = name
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class HelloWorld
    
    scala> var helloWorld = new HelloWorld
    helloWorld: HelloWorld = HelloWorld@74f143e1
    
    scala> helloWorld.sayHello()
    Hello,leo
    scala> print(helloWorld.getName) //也可以不加括号,如果定义方法时不带括号,则用方法时也不能带括号
    leo
    
    
    //getter与setter
    //定义不带private的var field,JVM会自动定义为private,并提供public的getter和setter方法
    //如果定义private 修饰field,则生成getter和setter也是private的
    //如果定义val filed,则只会生成getter方法
    //如果不希望生成setter和getter方法,则将field声明为private[this]
    
    

    自定义getter与setter

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student{
     private var myName = "leo"
     def name = "your name is" + myName
     def name_=(newValue:String){
      print("you cannot edit your name!!")
    }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val leo = new Student //()可有可无
    leo: Student = Student@4064c13a
    
    scala> print(leo.name)
    your name isleo
    scala> leo.name = "leo1" //相当于setter方法
    you cannot edit your name!!leo.name: String = your name isleo
    

    仅暴露field的getter方法

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student{
     private var myName = "leo" //private修饰,不暴露getter和setter方法,因此可以自定义
     def updateName(newName:String){
      if(newName == "leo1") myName = newName
      else print("not accpet this new name!!")
    }
    def name = "your name is "+myName
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val s = new Student()
    s: Student = Student@6ff347a9
    
    scala> s.name
    res30: String = your name is leo
    
    scala> s.updateName("tom")
    not accpet this new name!!
    scala> s.updateName("leo1")
    
    scala> s.name
    res33: String = your name is leo1
    

    private[this]的使用

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student{
     private var myAge = 0
     def age_=(newValue:Int){
      if(newValue > 0) myAge = newValue
      else print("illegal age!")
     }
     def age = myAge
     def older(s:Student)={ //用private[this]修饰的话会报错
      myAge > s.myAge
     }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val s1 = new Student
    s1: Student = Student@1c437904
    
    scala> s1.age = 20
    s1.age: Int = 20
    
    scala> val s2 = new Student
    s2: Student = Student@400f0e8e
    
    scala> s2.age = 25
    s2.age: Int = 25
    
    scala> s1.older(s2)
    res34: Boolean = false
    

    java风格的getter和setter

    // 在Scala 2.10.0之后已被废弃
    // 使用scala.beans.BeanProperty代替
    scala> import scala.beans.BeanProperty
    import scala.beans.BeanProperty
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student{
      @BeanProperty var name:String = _
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val s = new Student
    s: Student = Student@1166c9c5
    
    scala> s.setName("leo")
    
    scala> s.get
    getClass   getName
    
    scala> s.getName
    res39: String = leo
    
    

    辅助构造函数constructor

    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student{
     private var name = ""
     private var age = 0
     def this(name:String){
      this()
      this.name = name
     }
     def this(name:String,age:Int){
      this(name)
      this.age = age
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> var s1 = new Student()
    s1: Student = Student@51c959a4
    
    scala> val s2 = new Student("leo")
    s2: Student = Student@51a18b21
    
    scala> val s3 = new Student("leo",30)
    s3: Student = Student@40ef0af8
    

    主构造函数constructor

    //主constructor与类名放在一起,与java不同
    //类中没有定义在任何方法或者代码块中的代码,就是主constructor的代码
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student(val name:String,val age:Int){
      println("your name is "+name +",your age is "+age)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val s = new Student
    <console>:12: error: not enough arguments for constructor Student: (name: String, age: Int)Student.
    Unspecified value parameters name, age.
           val s = new Student
                   ^
    
    scala> val s = new Student("jom",23)
    your name is jom,your age is 23
    s: Student = Student@2d70f312
    
    //给默认值
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Student(val name:String="leo",val age:Int=30){ // 如果主constructor传入的参数什么修饰都没有,比如name:String ,那么如果类内部方法使用到了,则会声明为private[this] name;否则没有该field,就只能被constructor代码使用而已
      println(name+" "+age)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Student
    
    scala> val s1 = new Student
    leo 30
    s1: Student = Student@cf10c92
    

    内部类

    scala> import scala.collection.mutable.ArrayBuffer
    import scala.collection.mutable.ArrayBuffer
    
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Class{
      class Student(val name:String){}
      val students = new ArrayBuffer[Student]
      def getStudent(name:String)={
       new Student(name)
      }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Class
    
    scala> val c1 = new Class
    c1: Class = Class@539bb233
    
    scala> val s1 = c1.getStudent("leo")
    s1: c1.Student = Class$Student@48b01607
    
    scala> c1.students += s1
    res0: c1.students.type = ArrayBuffer(Class$Student@48b01607)
    
    scala> val c2 = new Class
    c2: Class = Class@475fb7
    
    scala> val s2 = c2.getStudent("leo")
    s2: c2.Student = Class$Student@5f9f1886
    
    scala> c1.students += s2
    <console>:15: error: type mismatch;
     found   : c2.Student
     required: c1.Student
           c1.students += s2
                          ^
    

    面向对象编程之对象

    1. object,相当于class的单个实例,通常在里面放一些静态的field或者method
    2. 第一次调用object的方法时,就会执行object的constructor,也就是object内部不在method中的代码;但是object不能定义接收参数的constructor
    3. 注意,object的constructor只会在第一次被调用时执行一次,以后再调用不会再次执行constructor
    4. object通常用于作为单例模式的实现,或者放class的静态成员,比如工具方法
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    object Person{
      private var eyeNum=2
      println("this Person object!")
      def getEyeNum = eyeNum
    }
    
    scala> Person.getEyeNum
    this Person object!
    res3: Int = 2
    

    伴生对象

    1. 如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
    2. 伴生对象伴生类和伴生对象必须放在一个.scala文件之中
    3. 伴生类和伴生对象,最大的特点就在于,互相可以访问private field
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(val name:String,val age:Int){
      def sayHello = println("Hi,"+name+",I guess you are "+age+"years old!"+Person.eyeNum)
    }
    object Person{
     private val eyeNum = 2
     def getEyeNum = eyeNum
    }
    
    scala> val p = new Person("TOM",30)
    p: Person = Person@101f2ca2
    
    scala> p.sayHello
    Hi,TOM,I guess you are 30years old!2
    
    

    让object继承抽象类

    1. object的功能其实和class类似,除了不能定义接收参数的constructor之外
    2. object也可以继承抽象类,并覆盖抽象类中的方法
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Hello(val message:String){
     def sayHello(name:String):Unit
    }
    object HelloImpl extends Hello("hello"){
     override def sayHello(name:String)={
      println(message+","+name)
    
    }
    }
    
    
    scala> HelloImpl.sayHello("world")
    hello,world
    
    
    

    apply方法

    1. object中非常重要的一个特殊方法,就是apply方法
    2. 通常在伴生对象中实现apply方法,并在其中实现构造伴生类的对象的功能
    3. 而创建伴生类的对象时,通常不会使用new Class的方式,而是使用Class()的方式,隐式地调用伴生对象的apply方法,这样会让对象创建更加简洁
    4. 比如,Array类的伴生对象的apply方法就实现了接收可变数量的参数,并创建一个Array对象的功能
    5. val a = Array(1,2,3,4,5)
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(val name: String)
    object Person{
      def apply(name:String)=new Person(name)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined object Person
    
    scala> val p1 = new Person("leo")
    p1: Person = Person@7698b7a4
    
    scala> val p2 = Person("leo")
    p2: Person = Person@374c40ba
    

    main方法

    1. 方法入口
    2. scala中main方法定义为def main(args:Array[String]),而且必须定义在object中
    object HelloWorld{
      def main(args:Array[String]){
       println("Hello World!!")
      }
    }
    
    1. 除了自己实现main方法之外,还可以继承App Trait,然后将需要在main方法中运行的代码,直接作为object的constructor代码;而且用args可以接受传入的参数
    object HelloWorld extends App{
      if(args.length > 0) println("hello," + args(0))
      else println("Hello World!!")
    }
    
    
    1. 运行上述代码,需要放入.scala文件中,然后使用scalac编译,再用scala运行class文件 scala -Dscala.time HelloWorld
    2. App Trait的工作原理为:App Trait继承自DelayedInit Trait,scalac命令进行编译时,会把继承App Trait的object的constructor代码都放到DelayedInit Trait的delayedInit方法中执行

    用object来实现枚举功能

    1. scala没有直接提供类似于java中的Enum这样的枚举特性,如果要实现枚举,则需要用object继承Enumeration类,并且调用Value方法来初始化枚举值
    object Season extends Enumeration{
     val SPRING,SUMMER,AUTUMN,WINTER = Value
    }
    
    scala> Season.SPRING
    res0: Season.Value = SPRING
    
    1. 还可以通过Value传入枚举值的id和name,通过id和toString可以获取,还可以通过id和name来查找枚举值
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    object Season extends Enumeration{
      val SPRING = Value(0,"spring")
      val SUMMER = Value(1,"summer")
      val AUTUMN = Value(2,"autumn")
      val WINTER = Value(3,"winter")
    }
    
    // Exiting paste mode, now interpreting.
    
    defined object Season
    
    scala> Season(0)
    res0: Season.Value = spring
    
    scala> Season.withName("spring")
    res1: Season.Value = spring
    
    scala> for(ele <- Season.values) println(ele)
    spring
    summer
    autumn
    winter
    

    面向对象编程之继承

    1. 让子类继承父类,与java一样,也是使用extends关键字
    2. 继承就代表,子类可以从父类继承父类的field和method;然后子类可以在自己内部放入父类所没有,子类特有的field和method;使用继承可以有效复用代码
    3. 子类可以覆盖父类的filed和method;但是如果父类用final修饰,field和method用final修饰,则该类是无法被继承的,field和method是无法被覆盖的
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person{
      private var name = "leo"
      def getName = name
    }
    class Student extends Person{
     private var score = "A"
     def getScore = score
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val s1 = new Student()
    s1: Student = Student@1530d0f2
    
    scala> s1.getScore
    res3: String = A
    
    scala> s1.getName
    res4: String = leo
    

    override和super

    1. 如果子类要覆盖一个父类中的非抽象方法,则必须使用override关键字
    2. override关键字可以帮组我们尽早的发现代码里的错误,覆写方法错了就会报错
    3. 在子类覆盖父类方法之后,如果我们在子类中就是要调用父类的被覆盖的方法,那就可以使用super关键字,显式地指定要调用父类的方法
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person{
     private var name="leo"
     def getName = name
    }
    class Student extends Person{
     private var score = "A"
     def getScore = score
     override def getName = "Hi,I'm "+ super.getName
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val st = new Student
    st: Student = Student@445c693
    
    scala> st.getName
    res5: String = Hi,I'm leo
    

    isInstanceOf和asInstanceOf

    1. 如果我们创建了子类的对象,但是又将其赋予了父类类型的变量,则在后续的程序中,我们又需要将父类类型的变量转换为子类类型的变量
    2. 使用isInstanceOf判断对象是否是指定类的对象,如果是的话,则可以使用asInstanceOf将对象转换为指定类型
    3. 注意,如果对象是null,则isInstanceOf一定返回false,asInstanceOf一定返回null
    4. 注意,如果没有用isInstanceOf先判断对象是否为指定类的实例,就直接用asInstanceOf转换,则可能会抛出异常
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person
    class Student extends Person
    val p:Person = new Student
    var s:Student = null
    if(p.isInstanceOf[Student]) s = p.asInstanceOf[Student]
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    p: Person = Student@2d7e6c8c
    s: Student = Student@2d7e6c8c
    
    scala> s
    res9: Student = Student@2d7e6c8c
    

    getClass和classOf

    1. isInstanceOf只能判断对象是否是指定类以及其子类的对象,而不能精确判断出,对象就是指定类的对象
    2. 如果要求精确地判断对象就是指定类的对象,那么就只能使用getClass和classOf了
    3. 对象.getClass可以精确获取对象的类,classOf[类]可以精确获取类,然后使用==操作符即可判断
    scala> :paste
    class Person
    class Student extends Person
    val p:Person = new Student
    p.isInstanceOf[Person]
    
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    p: Person = Student@5b95557f
    res11: Boolean = true
    
    scala> p.getClass == classOf[Person]
    res12: Boolean = false
    
    scala> p.getClass == classOf[Student]
    

    使用模式匹配进行类型判断

    1. 在实际开发中,比如spark的源码中,大量的地方使用模式匹配的方式来进行类型的判断
    2. 功能性上来说,与isInstanceOf一样,判断主要是该类以及该类的子类的对象即可,不是精准判断的
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person
    class Student extends Person
    val p:Person = new Student
    p match{
     case per:Person => println("its Person object")
     case _ => println("unkonwn type") 
    }
    
    // Exiting paste mode, now interpreting.
    
    its Person object
    defined class Person
    defined class Student
    p: Person = Student@7f4596d0
    

    protected

    1. 跟java一样,使用protected关键字修饰的filed和method,在子类中就不需要super关键字,直接就可以访问field和method
    2. 还可以使用protected[this],则只能在当前子类对象中访问父类的field和method,无法通过其他子类对象访问父类的field和mehtod
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person{
     protected var name:String="leo"
     protected[this] var hobby:String = "game"
    }
    class Student extends Person{
     def sayHello = println("Hello,"+name)
     def makeFriends(s:Student){
      println("my hobby is "+hobby + ",your hobby is " +s.hobby)
     }
    }
    
    // Exiting paste mode, now interpreting.
    
    <pastie>:20: error: value hobby is not a member of Student
      println("my hobby is "+hobby + ",your hobby is " +s.hobby) 
    

    调用父类的constructor

    1. 每个类可以有一个主constructor和任意多个辅助constructor,而每个辅助constructor的第一行都必须是调用其他辅助constructor或者是主constructor;因此子类的辅助constructor是一定不可能直接调用父类的constructor的
    2. 只能在子类的主constrctor中调用父类的constructor
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(val name:String,val age:Int)
    class Student(name:String,age:Int,var score:Double) extends Person(name,age){
     def this(name:String){
      this(name,0,0)
     }
     def this(age:Int){
      this("leo",age,0)
     }
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    

    匿名内部类

    1. 在scala中匿名子类非常常见,相当于java匿名内部类
    2. 定义一个类没有名称的子类,并直接创建其对象,然后将对象的引用赋予一个变量,之后甚至可以将该匿名子类的对象传递给其他函数
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    class Person(protected val name:String){
     def sayHello = "Hello,I'm " + name
    }
    val p = new Person("leo"){
     override def sayHello = "Hi,I'm "+name
    }
    def greeting(p:Person{def sayHello:String}){
      println(p.sayHello)
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    p: Person = $anon$1@628b9af5
    greeting: (p: Person{def sayHello: String})Unit
    
    scala> p.sayHello
    res5: String = Hi,I'm leo
    
    scala> greeting(p)
    Hi,I'm leo
    

    抽象类

    1. 和java同样的原理
    scala> :paste
    // Entering paste mode (ctrl-D to finish)
    
    abstract class Person(val name:String){
     def sayHello:Unit
    }
    class Student(name:String) extends Person(name){
     def sayHello:Unit = println("Hello, "+name) //可以省略override
    }
    
    // Exiting paste mode, now interpreting.
    
    defined class Person
    defined class Student
    
    scala> val s = new Student("jike")
    s: Student = Student@49bcd90d
    
    scala> s.sayHello
    Hello, jike
    
    

    抽象field

    1. 如果在父类中,定义了field,但是没有给出初始值,则此field为抽象field
    2. 抽象filed意味着,scala会根据自己的规则,为var或val类型的field生成对应的getter和setter方法,但是父类中没有该field的
    3. 子类必须覆盖field,以定义自己的具体field,并且覆盖抽象field,不需要使用override关键字
    abstract class Person{
     val name :String
    }
    
    class Student extends Person{
     val name :String = "leo"
    }
    
    scala> val s = new Student
    s: Student = Student@48c2391
    
    scala> s.name
    res9: String = leo
    
  • 相关阅读:
    钱多,人傻,快来快来
    Rabbitmq的使用及Web监控工具使用
    Fiddler的配置
    哪个微信编辑器比较好用?
    js手机号批量滚动抽奖代码实现
    Webform和MVC,为什么MVC更好一些?
    自学MVC看这里——全网最全ASP.NET MVC 教程汇总
    客如云系统访谈
    Asp.Net MVC2.0 Url 路由入门---实例篇
    架设自己的FTP服务器 Serv-U详细配置图文教程
  • 原文地址:https://www.cnblogs.com/sky-chen/p/10093776.html
Copyright © 2020-2023  润新知