• 学好Spark/Kafka必须要掌握的Scala技术点(二)类、单例/伴生对象、继承和trait,模式匹配、样例类(case class)


    3. 类、对象、继承和trait

    3.1 类

    3.1.1 类的定义

    Scala中,可以在类中定义类、以在函数中定义函数、可以在类中定义object;可以在函数中定义类,类成员的缺省访问级别是:public

    //在Scala中,类不用声明为public
    //Scala源文件中可以包含多个类,所有这些类都具有公有可见性
    class Person {
      //val修饰的变量是只读属性,相当于Java中final修饰的变量,只提供get()
      val id = "1"
      //var修饰的变量,提供get()和set()
      var age: Int = 18
      //类私有字段,只有本类和本类的伴生对象可以访问
      private var name = "zs"
      //对象私有字段只有本类能访问
      private[this] val pet = "xq"
    }
    
    /**(单例对象,静态对象)
      * 伴生对象:与class名相同,并且在同一个文件中*/
    object Person {
      def main(args: Array[String]): Unit = {
        val p = new Person
    //    p.id = "2"//    p.pet
        println(p.id +":"+p.age+":"+p.name)
        p.name = "ls"
        p.age = 20
        println(p.age+":"+p.name)
      }
    }
    

    3.1.2 构造器

    Scala主要分主构造器和辅助构造器两种:

    主构造器里面的变量会被执行,方法会被加载,调用的方法会被执行

    辅助构造器(相当于重载的构造函数)不可以直接调用超类的主构造器

    /**每个类都有主构造器,主构造器的参数直接放置类名后面,可以在主构造器中对字段赋值,对于主构造器中参数已赋值的在new的时候可以不再赋值
    private[com.bigdata] class Study{}:只有com.bigdata或其子包下的类能访问Stu
    
    class Stu(name:String){}:构造参数name没有val、var修饰
    
    相当于private[this] name:String ,只有本类能访问
     class Stu private(name:String){}:private修饰主构造器(私有构造器),只有伴生对象能new */
     
    class Student(val name: String, val age: Int) {
      //主构造器会执行类定义中的所有语句
      println("执行主构造器")
      try {
        println("读取文件")
        throw new IOException("io exception")
      } catch {
        case e: NullPointerException => println("打印异常Exception : " + e)
        case e: IOException => println("打印异常Exception : " + e)
      } finally {
        println("执行finally部分")
      }
      
      private var gender = "male"
      
      //用this关键字定义辅助构造器
      def this(name: String, age: Int, gender: String){
        //每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
    this(name, age)
    
        this.gender = gender
      }
    }
    

    3.1.3 Class

    Scala中类可以通过classOf[A]获取类型,Object单例/伴生只能通过.getClass获取。

    classOf和getClass区别:

    getClass方法得到的是Class[A]的某个子类,而classOf[A]得到是正确的 Class[A],但是去比较的话,这两个类型是equals为true的。这种细微的差别,体现在类型赋值时,因为java里的Class[T]是不支持协变的,所以无法把一个 Class[_ < : A] 赋值给一个 Class[A]。

    类型检查和转换:

    Scala Java
    obj.isInstanceOf[C]:判断obj是否属于C类型 obj instanceof C
    obj.asInstanceOf[C]:转换 (C)obj
    classOf[C] C.class

    3.2 对象

    3.2.1 单例对象和伴生对象

    1.单例对象
    在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的。主要作用:
    1)存放工具方法和常量
    2)高效共享单个不可变的实例
    3)单例模式
    
    2.伴生对象
    单例对象,不需要new,用【类名.方法】调用单例对象中的方法
    伴生对象
    在scala的类中,与类名相同且与该类在同一个文件的对象叫伴生对象。类和伴生对象之间可以相互访问私有的方法和属性,但类的字段被private[this]修饰的只有本类能访问
    

    3.2.2 应用程序对象

    Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。

    object AppObjectDemo extends App{
      //不用写main方法
      println("Scala")
    }
    

    3.2.3 apply和unapply方法

    通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用。

    apply方法有点类似于java中的构造函数,接受构造参数变成一个对象。

    unapply方法就刚好相反,它是接收一个对象,从对象中提取出相应的值,主要用于模式匹配(后文阐述)中。

    def main(args: Array[String]) {
        //调用了Array伴生对象的apply方法
        //def apply(x: Int, xs: Int*): Array[Int]
        //arr1中只有一个元素5
        val arr1 = Array(5)
    //def apply[T: ClassTag](xs: T*): Array[T] = {}
        var arr2 = Array[Int](8)
        println(arr1.toBuffer)
        //new了一个长度为5的array,数组里面包含5个null(没有指定泛型)
        var arr2 = new Array(5)
    }
    

    3.3 继承和trait

    在Scala中继承类的方式和Java一样都是使用extends关键字,继承多个类后面有with关键字。

    Scala中没有接口,而是trait即特质,类似Java1.8中的接口,其中可以包含抽象方法也可以有已实现的方法。

    在Scala中重写一个非抽象的方法(没有被实现)必须使用override修饰符,抽象方法可以使用也可以不使用override。

    trait Flyable {
      def fly(): Unit = { println("I can fly")  }
    }
    abstract class Animal {
      def run(): Int
      val name: String
    }
    /*class Human extends Animal with Flyable
      class Human extends Flyable with其他trait(特质)
    */
    class Human extends Animal with Flyable {
      val name = "lz"
      //t1、t2、、tn打印n次ABC,t1=(1, 2, 3,4)(a->1,b->2,c->3,d->4)
      val t1, t2,t3, (a, b, c,d) = {
        println("ABC")
        (1, 2, 3,4)
      }
    //scala中重写一个非抽象方法必须使用override关键字
      override def fly(): Unit = { println("123") }
    //重写抽象方法可以使用也可以不使用override关键字
      def run(): Int = { 1 }
    }
    object Main {
      def main(args: Array[String]): Unit = {
        val h = new Human
        println(h.t1+":"+h.a+":"+h.b+":"+h.c+":"+h.t2)
      }
    }
    

    4. 模式匹配和样例类

    4.1 模式匹配

    Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如替代Java中的switch语句、类型检查等。

    并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配。

    // 1. 匹配字符串
    import scala.util.Random
    object Case01 extends App {
      val arr = Array(1, 2, 3)
      val i = arr(Random.nextInt(arr.length))
      i match {
        case 1 => {println(i)}
        case 2 => {println(i)}
    //下划线_:代表匹配其他所有类似于switch语句中default
        case _ => {println(i)}
      }
    }
    
    // 2. 匹配类型
    import scala.util.Random
    object Case02 extends App {
      val arr = Array("a", 1, -2.0, Case02)
      val elem = arr(Random.nextInt(arr.length))
      println(elem)
      elem match {
        case x:Int => {println("Int"+x)}
    //模式匹配时可以加守卫条件,如果不符合守卫条件,走case_
        case y:Double if(y>=0) => println("Double "+ y)
        case Case02 => {println("Int"+Case02)}
        case _ => {println("default")}
      }
    }
    
    // 3. 匹配数组
    object Case03 extends App {
      /*  val arr = Array(0, 3, 5)
        arr match {
          case Array(1,x,y) => println(x+":"+y)
          case Array(0) => println("only 0")
            //表示匹配首元素是0的数组
          case Array(0,_*) => println("0 ...")
          case _ => println("else")
        }*/
      /*  val lst = List(0,-1,1,2)
        //head首元素,tail除首元素之外的元素 take从1开始取
        println(lst.head+":"+lst.tail+":"+lst.take(1))
        lst match {
            //首元素0,Nil代表空列表
          case 0 :: Nil => println("only 0")
            //只有两个元素
          case x :: y :: Nil => println(s"x:$x--y:$y")
          case 0 :: x => println(s"0...$x")//head和tail
          case _ => println("else")
        }*/
      val tup = (-1.2, "a", 5)
      tup match {
        //元组有几个元素,case后跟的元组也要有几个元素
        case (1, x, y) => println(s"hello 123 $x , $y")
        case (_, z, 5) => println(z) //前两个元素为任意值
        case _ => println("else")
      }
      val lst1 = 9 :: (5 :: (2 :: Nil))
      val lst2 = 9 :: 5 :: 2 :: List()
      println(lst2+":"+lst1)//952:952
    }
    

    4.2 样例类

    可用于模式匹配、封装数据(多例)。case class多例,后面跟构造函数;case object是单例的:

    import scala.util.Random
    case class Task(id:String)
    case class HeartTime(private val time:Long)//构造case class可new可不new
    case object CheckTimeOut
    
    object Main {
        def main(args: Array[String]) {
            val arr = Array(CheckTimeOut, HeartBeat(88888), Task("0001"))
            val a = arr(Random.nextInt(arr.length))
    
           a match {
                case Task(id) => {println(s"$id")}//取id值 固定写法
                case HeartTime(time) => {println(s"$time")}
                case CheckTimeOutTask => {
                    println("check")
                }
                
                //匹配其他情况
                case _ => prinln("do something")
             }
        }
    }
    

    关注微信公众号:大数据学习与分享,获取更对技术干货

  • 相关阅读:
    module(JS模块系统)
    Sass 教程
    Vue编写的页面部署到springboot网站项目中出现页面加载不全问题
    vue安装教程
    李大庆 软件工程 课后作业(一) 自我介绍
    课后作业(一)
    软工假期预习作业1
    浅谈C#中 加密方式
    C# 日志帮助类
    开荒笔记---UML类图之间的几种关系介绍
  • 原文地址:https://www.cnblogs.com/bigdatalearnshare/p/14104916.html
Copyright © 2020-2023  润新知