scala - 基础知识

1.def 定义的是一个方法,用下划线可以转换为方法
2.window 换行符是/r/n linux /n
《逐云》

Scala 概述 2.11.8

  • 优雅,速度快,融合hadoop生态圈。未来或许会替代MR,个人认为不可能。
  • 最关键的就是 面向对象编程面向函数编程
Windows 安装Scala编译器
  • 下载scala-2.11.8.msi后点击下一步就可以了。
Linux安装Scala编译器
  • 跟JDK一样,解压环境变量

Scala 基本语法

1. 变量声明
// object 类型代表 一个helloworld的实例
object  helloworld {

  // 在定义方法的时候,与java类型相反 变量名:数据类型
  def main(args: Array[String]): Unit = {
    //常量
    val num = 100 ;
    // 变量两种形式 ,
    var  str = "hell boy" ;
    var str2: String = "ni bu zhidao shiqing "
  }
}  
2. 常用类型
  • 与 java基本数据类型一致,重点是double无包装类型
3. 条件表达式
  • if else 的逻辑判断

    // Unit 代表方法执行后的返回类型
    def method_one(str: String): Unit = {
    
    val num = 3;
    
    // if else 逻辑判断
    val num2 = {
      if (num > 5) 1 else if (num > 2) 2 else -1;
    }
    val num3 = if (num > 4) 1 else (); //输出  num3   equal ()
    println("num2   equal " + num2);
    println("str   equal " + str);
    println("num3   equal " + num3);
    
    }  
    
    >   输出结果  num2   equal 2
    >            str   equal rui
    >            num3   equal ()                    
    

提示
默认返回的是常量值

val unit = method_one(“rui”);

println(“method_one ” + unit) //输出结果 method_one (),() 就等于 unit

4. 块表达式
  • {…} 内部就被称为块表达式

     val num2 = {
      if (num > 5) 1 else if (num > 2) 2 else -1;
    }
    
5.循环表达式
  • for 循环方式一

      // 1 to 100 是一个区间 Range,每次返回的一个值都赋值给 i
    
        for (i <- 1 to 100) {
            println(i)
          }
    
  • for 循环遍历数组

    // 数组代表一个区间
    val arr  = Array ('a', "b" , "av") ;
    
    for (i <- arr) {
      println(i)
    }
    
  • 高级for循环

     // 每个生成器都可以带一个条件,注意if前面 无 分号
    // 双重 for循环
    for (i <- 1 to 3 ; j <- 1 to 3 if i != j ) {
        // 满足条件进入循环体 
        print(j + "  ")
       // 2 3 1 3 1 2
    } 
    
6.调用方法函数
  • Scala中的+ - * / %等操作符的作用与Java一样,位操作符 & | ^ >> <<也一样。只是有
    一点特别的:这些操作符实际上是方法。通常来说不需要自定义返回值,系统会正常判断,但是对于递归函数必须要返回值

    例子  
         val str1 = num.+(str)
         val i = num.+(num2)
         println(str1)  // 100hell boy
         println(i)     // 1100
    
    > 返回值类型可以自动推断出来 不需要重新定义
    
7.数组、映射、元组、集合
  • 数组元素的添加,删除,打印

    1. 定义数组  
        定义一个长度为10,类型为String的数组
        val arr1 = new Array[String](10);
        println(arr1)  //[Ljava.lang.String;@58651fd0输出的是hash值  
    
    2. 打印数组内容
    //2. 将数组转换为数组缓冲就可以看到里面的内容
     println(arr1.toBuffer) //ArrayBuffer(null, null, null, null, null, null, null, null, null, null)
    
    3. 向数组中追加内容
    
    //向数组中追加元素
    arr3.+=("a"); println(arr3)
    
    4. 向数组中添加数组,但是原来的长度,内容都不会变量
    
      //向数组中追加数组
        val arr4 = Array[Int](1,2);
        val arr5 = Array[Int](3,4,5);
        // ++ 集合不会改变arr4
        val arr6= arr4.++(arr5) 
    
    5. 数组元素的插入或者移除
         val  array = Array(1,2,3,4);
         val arr1 = ArrayBuffer(1,2,3,4)
        // 前面是小标位置,后面的是元素内容
        arr1.insert(0,-2,-3)
        println(arr1.toBuffer)
        arr1.remove(arr1.length)
    
    6. 数组遍历
    
            //初始化一个数组
            val arr = Array(1,2,3,4,5,6,7,8)            
            for(i <- arr) {
              println(i)
            }
            //读取的是小标反转
            for(i<- (0 until  arr.length).reverse){
              print(arr(i))
            } 
    7.数组过滤
    
        val arr = Array(1, 2, 3, 4, 5, 6, 7, 8, 9)
        // yield 将原始数组转换为一个新的数组,原始数组不变
        val arr1 = for( i <- arr if(i % 2 ==0)) yield i * 10;
        println(arr1.toBuffer)
        println(arr.toBuffer)
        // _ 就代表变量遍历出来的每一个元素
        val a = arr1.filter(_ % 2 ==0).map(_* 100);print(a.toBuffer)  
    
        println(a.sum)
        println(a.max)
        println(a.min)
        println(a.sorted)
    
  • 映射关系map

       val info = Map("name"->"tom","age"->"23","sex"->"nan")
        //有值返回值,没有值返回默认值
        println(info("name"));println(info.getOrElse("pp",0)) 
    
        在映射关系中有个两个map类型,一个长度是否可变来区分
        一个是immutable包下的Map,该Map中的内容不可变;另一个是mutable包下的Map,该Map中的内容可变
    
  • 元组 也是一种映射关系,可以存储各种类型数据

         // 定义一个元组
        val t = ("123",3.131313,"Pp",1)
         // 元组的下标是从一个开始的
        println(t._1)
        // 将对偶的集合转换为映射
        val arr = Array(("p",11),("t",12))
        arr.toMap
    
        // 拉杆操作
        val rui = Array(10,20,30)
        val liu = Array("a","b")
    
        // 对应值进行捆绑
        val liuguangrui = rui.zip(liu)
        val liuguangrui2 = rui.zipAll(liu,12,"ll")
        println(liuguangrui.toBuffer)
        println(liuguangrui2.toBuffer)
    
        输出内容
        ArrayBuffer((10,a), (20,b))
        ArrayBuffer((10,a), (20,b), (30,ll))
    
8. 集合
  • Scala的集合有三大类:序列Seq、Set、映射Map,所有的集合都扩展自Iterable特质
    在Scala中集合有可变(mutable)和不可变(immutable)两种类型,immutable类型的集合初始化后就不能改变了(注意与val修饰的变量进行区别)

  • List集合

    val left = List(1,2,3)
    val right = List(4,5,6)
    val uni = left ++ right
    println()
    println(uni.toArray.toBuffer)
    //    println(left.++(right).toBuffer)  //两个+ 代表加的集合
    //    println(left.++:(right).toBuffer)
    //    println(left.+:("sdfdsf").toBuffer) //:就相当于头部
    //    println(left.:+("sdfdsf").toBuffer.head) //第一个元素
    //    println(left.:+("sdfdsf").toBuffer.tail) //除一个元素外的其他元素
    
  • Set集合

    // 两个集合交集
    val ints = set & set1
    //在第一个集合基础上 去掉第二个集合重复元素
    val ints1 = set -- set1
    //并集
    val ints2 = set ++ set1
    // 返回第一个不同于第二个集合元素
     val ints3 = set1 &~ set  //set1.diff(set)
     // 大于6的元素
    val i = set.count(_>=6)
     // 从角标0 开始 取代 2个元素
     val ints4 = set.slice(0,2)
     val unit = set1.subsets(2).foreach(x=>println(x))
    定义一个可变长度
    set1 += 1 ; println(set1.toBuffer)
    set1.add(2); println(set1.toBuffer)
    set1 ++=Set(1,4,5);println(set1)
    
  • Map集合

     // 长度不可以改变,不可以去添加或者删除
     val map1 = Map("rui" -> 12,"wen"->21) ; println(map1.toBuffer)
      val keys = map1.keys;println(keys.toBuffer)
      val set = map1.keySet;println(set.toBuffer)  
    
      // 长度可以变化
        val user =mutable.HashMap("zhangsan"->50,"lisi" -> 100)
        user +=("wangwu" -> 30);println(user.toBuffer) 
        user("zhangsan") = 55;println(user.toBuffer) //修改键
        user -=("zhangsan") //删除键
        user += ("zhangsan" -> 60, "lisi" -> 50) //添加键
        user.remove("zhangsan0")  // 删除键
    
    
      // 遍历map方法 
        for((x,y) <- user) println(x+" -> "+y)   // for循环
        for(x<- user.keys) println(x+" -> "+user(x)) //键集 获取值
        user.foreach{case (x,y) => println(x+" -> "+y)} //foreach 循环遍历
    

类、对象、继承、特质

    • 类型一

      // 主构造器 会执行类中定义所有语句,方法解析不执行
      class Person  (val nameStr:String,val age : Int){
         // val 修饰的变量,只有get方法 无set方法
        val  id = "9527".toInt
        val  str: String  = "rui"
        //类私有字段,只能在类的内部使用
        private var name: String = "唐伯虎"
        //对象私有字段,Person类的方法只能访问到当前对象的字段
        private[this] val pet = "小强"
      
        var gender = "nan"  ; //get,set都有
        //辅助构造器,第一行必须要调用主构造器
      //  def this(name : String,age :Int,gender:String){
      //    this(name,id);
      //    this.gender = gender
       // }
      }
      
    • 类型二

      class Queen (val name : String ,prop : Array[String],private var  age : Int=23) {
      
         println(prop.length)
        // 由于age被private修饰,隐藏 age , name 都等同于被private修饰
        def description = name + " is " + age + " years old with " + prop.toBuffer
      }
      object Queen{
        def main(args: Array[String]) {
          //私有的构造器,只有在其伴生对象中使用
          val q = new Queen("itcast", Array("黑马", "博学谷"), 10)
          println(q.description)
        }
      }
      
  • 对象 由于在scala中没有静态方法字段,因此通过object达到同静态方法字段同样的效率

    • 伴生对象 1. 在一个文件中, 类名与object名字相同,彼此可以相互访问

      // 通过object达到同静态方法字段同样的效率
      class SingleDemo {
      
        def main(args: Array[String]): Unit = {
          val demo: SingleDemo = SessionFactory.getSession()
          println(demo)
        }
      }
      object SessionFactory{
        //该部分相当于java中的静态块
        var counts = 5
        val sessions = new ArrayBuffer[SingleDemo]()
        while(counts > 0){
          sessions += new SingleDemo
          counts -= 1
        }
        //在object中的方法相当于java中的静态方法
        def getSession(): SingleDemo ={
          sessions.remove(0)
        }
      }
      
  • Scala中isInstanceOf 和 asInstanceOf 区别

is是先判断 q.isInstanceOf(a)q是a的一个实例,只能判断q是a子类或者其实体类

q.asInstanceOf(a)将q转为a,通常来说都是先判断后转

如果对象是 null,则 isInstanceOf 一定返回 false, asInstanceOf 一定返回 null;

//判断p是否为Person4类的实例
println(p.isInstanceOf[Person4])//true
//判断p的类型是否为Person4类
println(p.getClass == classOf[Person4])//false
//判断p的类型是否为Student4类
println(p.getClass == classOf[Student4])//true  

可以向下面这样写
 val p:Person5=new Student5
p match {
  // 匹配是否为Person类或其子类
  case per:Person5 => println("This is a Person5's Object!")
  // 匹配所有剩余情况
  case _  =>println("Unknown type!")
}
  • 匿名内部类

    //匿名内部类
    class Person8(val name:String) {
      def sayHello="Hello ,I'm "+name
    }
    
    class GreetDemo{
    
      def hell(person8 : Person8{
        def sayHello : String
      }) ={
        println(person8.sayHello)
      }
    }
    
    object GreetDemo {
      def main(args: Array[String]) {
        //创建Person8的匿名子类对象
        val p=new Person8("tom")
        val g=new GreetDemo
        g.hell(p)
      }
    }
    
  • 重写抽象类

    // 抽象方法
    abstract class Person9 (val name:String){
      //必须指出返回类型,不然默认返回为Unit
      def sayHello:String
      def sayBye:String
    
    }
    // 在子类中覆盖抽象类的抽象方法时,可以不加override关键字;
    class Student9(name:String) extends Person9(name){
      //必须指出返回类型,不然默认
      def sayHello: String = "Hello,"+name
      def sayBye: String ="Bye,"+name
    }
    object Student9{
      def main(args: Array[String]) {
        val s = new Student9("tom")
        println(s.sayHello)
        println(s.sayBye)
      }
    }  
    
    
    //抽象类中 字段没有给出初始值的话,子类集成抽象类后需要复写   
    
    abstract class Person10 (val name:String){
    //抽象fields
        val age:Int
    }
    class Student10(name: String) extends Person10(name) {
       val age: Int = 50
    }
    
9. Trait 用法
  • Trait 类似于 抽象类 或者接口 类与trait之间是继承的关系,trait与trait之间是with关系
  • 继承 trait 获取的field直接被添加到子类中
  • 子类调用父类的方法
  • 必须覆盖抽象类中 field字段
9.1 实例对象中指定混入某个trait
    trait LoggedTrait {
      // 该方法为实现的具体方法
      def log(msg: String) = {println("sdfdsf")}

    }
    trait MyLogger extends LoggedTrait{
      // 覆盖 log() 方法
      override def log(msg: String) = println("log: " + msg)

    }
    class PersonForMixTraitMethod(val name: String) extends LoggedTrait {

      def sayHello = {
        println("Hi, I'm " + this.name)
        log("sayHello method is invoked!")
      }
    }

    object PersonForMixTraitMethod{
      def main(args: Array[String]) {
        val tom= new PersonForMixTraitMethod("Tom").sayHello //结果为:Hi, I'm Tom sdfdsf
        // 使用 with 关键字,指定混入MyLogger trait
        val rose = new PersonForMixTraitMethod("Rose") with MyLogger
        rose.sayHello
        // 结果为:     Hi, I'm Rose
        // 结果为:     log: sayHello method is invoked!

      }
    }
9.2 trait之间继承关系
  • //1. 类与类之间 先走父类
  • //2. trait之间先走父类,从左到右的顺序
  • //3. 最后走本类的苟泽

    //1
    class Person_One {

    println(“Person’s constructor!”)
    }

    //2
    trait Logger_One {
    println(“Logger’s constructor!”)
    }

    //3
    trait MyLogger_One extends Logger_One {
    println(“MyLogger’s constructor!”)
    }
    //4
    trait TimeLogger_One extends Logger_One {
    println(“TimeLogger’s contructor!”)
    }
    // 1. 类与类之间 先走父类
    //2. trait之间先走父类,从左到右的顺序
    //3. 最后走本类的苟泽

    //5
    class Student_One extends Person_One with MyLogger_One with TimeLogger_One {
    println(“Student’s constructor!”)
    }
    object exe_one {
    def main(args: Array[String]): Unit = {
    val student = new Student_One
    //执行结果为:
    // Person’s constructor!
    // Logger’s constructor!
    // MyLogger’s constructor!
    // TimeLogger’s contructor!
    // Student’s constructor!
    }
    }

1. 模式匹配和样例类

  • case匹配模式数据类型与内容匹配

        val arr = Array("hadoop", "zookeeper", "spark")
      val name = arr(Random.nextInt(arr.length))
      // 内容匹配
      name match {
        case "hadoop" => println("大数据分布式存储和计算框架...")
        case "zookeeper" => println("大数据分布式协调服务框架...")
        case "spark" => println("大数据分布式内存计算框架...")
        case _ => println("我不认识你...")
      }
    
      val arr1 = Array("hello", 1, 2.0, CaseDemo01)
      val v = arr1(Random.nextInt(4))
    
      // 类型匹配
      v match {
            case x: Int => println("Int " + x)
            case y: Double if(y >= 0) => println("Double "+ y)//  匹配的时候还可以添加守卫条件
            case z: String => println("String " + z)
            case _ => throw new Exception("not match exception")
      }  
    
        // 集合匹配
        val lst = List(3, -1)
          lst match {
            case 0 :: Nil => println("only 0")
            case x :: y :: Nil => println(s"x: $x y: $y")
            case 0 :: tail => println("0 ...")
            case _ => println("something else")
          }
        // 元组匹配
          val tup = (2, 3, 7)
          tup match {
            case (1, x, y) => println(s"1, $x , $y") //输出格式,前面必须是s
            case (_, z, 5) => println(z)
            case  _ => println("else")
          }
    
         //引用类型匹配
    
         val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
    
          arr(Random.nextInt(arr.length)) match {
            case SubmitTask(id, name) => {
              println(s"$id, $name")
            }
            case HeartBeat(time) => {
              println(time)
            }
            case CheckTimeOutTask => {
              println("check")
            }
          }
    
    
        //map类型匹配
    
          val map = Map("a" -> 1, "b" -> 2)
            val v = map.get("b") match {
              case Some(i) => i
              case None => 0
            }
    
        //PartialFunction[A, B] A代表参数类型 B代表返回值
    
        def func1: PartialFunction[String, Int] = {
            case "one" => 1
            case "two" => 2
            case _ => -1
          }
    
        协变、逆变、非变总结
           C[+T]:如果A是B的子类,那么C[A]是C[B]的子类。
           C[-T]:如果A是B的子类,那么C[B]是C[A]的子类。
           C[T]: 无论A和B是什么关系,C[A]和C[B]没有从属关系。
    

Scala中的上下界 (重点)

  • Scala的上下边界特性允许泛型类型是某个类的子类,或者是某个类的父类;

    (1) U >: T

    这是类型下界的定义,也就是U必须是类型T的父类(或本身,自己也可以认为是自己的父类)。

    (2) S <: T

    这是类型上界的定义,也就是S必须是类型T的子类(或本身,自己也可以认为是自己的子类)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值