Scala面向对象

面向对象

创建类和对象

package com.bigdata.scala03
/**
* 学生类
* 属性:姓名、性别、年龄,地址
*
* 行为:学习
*/
class Student {
    //成员变量: 最小化原则
    /**
    * 成员变量初始化的_表示占位符。
    * 占位符是在成员变量使用的时候需要被具体的数
    据替换的
    *
    * val不能和_一起使用。
    * 成员变量使用_初始化不能省略数据类型
    *
    */
    var name:String = _
    var sex:String = _
    var age:Int = _
    
    //成员方法
    def study(): Unit ={
    	println("好好学习")
    }
}
package com.bigdata.scala03
object StudentDemo {
    def main(args: Array[String]): Unit ={
        val stu = new Student
        stu.name = "张三"
        stu.age = 18
        stu.sex = "male"
        println(s"name=${stu.name},sex=${stu.sex},age=${stu.age}")
        stu.study()
    }
}

@BeanProperty

/**
* @BeanProperty 生成getter和setter方法,使创建的类可以调用getter和setter方法
*/
@BeanProperty
var name:String = _

private修饰符

成员变量的本质是方法

private修饰成员变量,其实就是将get和set私有了。

private修饰成员可以在本类及伴生对象中使用

private[this]修饰成员只能在本类中使用

伴生对象和伴生类

在同一个文件中,如果class和object的名字一样,那么他们互为伴生

这个class就是伴生类,这个object就是伴生对象

class Student{}
object Student{}
  • 当一个单例对象和某个类共享一个名称时,这个单例对象称为 伴生对象。 同理,这个类被称为是这个单例对象的伴生类。
  • 类和它的伴生对象可以互相访问其私有成员。
  • 使用伴生对象来定义那些在伴生类中不依赖于实例化对象而存在的成员变量或者方法。(静态的成员变量和方法)

非静态的代码编写在class中

静态的代码编写在object中

单例对象

  • 单例对象是一种特殊的类,有且只有一个实例。和惰性变量一样,单例对象是延迟创建的,当它第一次被使用时创建。
  • 当对象定义于顶层时(即没有包含在其他类中),单例对象只有一个实例。
  • 当对象定义在一个类或方法中时,单例对象表现得和惰性变量一样。
  • 一个单例对象是就是一个值。单例对象的定义方式很像类,但是使用关键字 object:
object Box

构造函数

/**
* class Dog() 后面的构造函数是主构造
* 主构造有且只有一个
* 如果需要使用多个构造,就需要加上辅助构造
* 辅助构造可以有0或n个
* 辅助构造必须在第一条语句中调用主构造
*/
class Dog() {
    var name:String = _
    var age:Int = _
    
    def this(a:Int){
        this()
        println("辅助构造---------")
    }
    
    def this(name:String){
        this()
        println("辅助构造---------")
    }
}

object DogDemo{
    def main(args: Array[String]): Unit ={
        val dog = new Dog(10)
        dog.name = "哮天犬"
        dog.age = 3000
        println(dog.name + "," + dog.age)
    }
}
/**
* Cat(name:String,age:Int): name和age是局部变量
* Cat(var name:String,var age:Int):name和age是可读写成员变量
* Cat(val name:String,val age:Int):name和age是只读成员变量
*
* 辅助构造的参数不能使用val和var修饰
*/
class Cat(var name:String,var age:Int) {
    var sex:String = _
    
    def this(sex:String){
        this("",1)
        this.sex = sex
    }
}

object CatDemo{
    def main(args: Array[String]): Unit ={
        val cat = new Cat("机器猫",2)
        println(s"${cat.name},${cat.age},${cat.sex}")
        println(cat)
    }
}

构造函数私有化

//主构造私有
class Pig private() {
    var name:String = _
    var age:Int = _
    
    //辅助构造私有
    private def this(name:String){
        this()
        this.name = name
    }
}

继承

scala使用extends关键字表示继承

私有的成员不能被继承

Scala中的类之间的继承也是单继承

重写

  • Scala中重写使用override关键字
  • Scala中成员变量和方法都可以覆写。
  • Scala中成员变量的本质是方法,所以可以被重写。
  • final修饰的方法和val常量不能被重写。

为什么只能覆写val修饰的成员变量???
因为var修饰的是变量可以直接修改。val修饰的是常量,只能通过覆写的方式修改

super

scala中super只能访问父类的方法,不能方法成员变量

class Animal {
    val name:String = "Animal"
    var age:Int = _
    
    def xx = name
    
    def eat(): Unit ={
    	println("吃....")
    }
}

class Tigger extends Animal {
    def show(): Unit ={
        println(super.xx)
        println(super.name)//error
    }
}

编写一个单例的饿汉式

/**
* 饿汉式:
* 1、构造私有
* 2、创建一个私有的静态的对象
* 3、提供公共静态方法返回对象
*/
class Coder private{
}

object Coder{
    private val coder = new Coder
    
    def getInstance(): Coder ={
    	coder
    }
}

多态

多态:多种形态、多种状态
形/状态:代码编译时和运行时的状态
单态:编译时和运行时的状态时一样的

Dog god = new Dog();
//Dog god 编译时状态 Dog
//new Dog() 运行时状态 Dog

多态:编译时和运行时的状态时状态不一样的

Pet pet = new Dog();
//Pet pet 编译时状态 Pet
//new Dog() 运行时状态 Dog

面向对象的多态:编译时和运行时的状态体现出了两种状态,编译时状态时运行时状态的父类。

为什么要用多态?什么时候用多态??

多态的好处:代码的扩展性增强
多态的使用场景:作为参数和返回值的时候

多态中的类型转换

对象.isInstanceOf[T] 判断对象是不是属于T类型

对象.asInstanceOf[T] 将对象转换成T类型

抽象

  • 在scala中使用abstract表示抽象
  • scala中有抽象类、抽象方法、抽象字段
  • abstract只能修饰类。
  • 抽象类的子类覆写方法或字段的时候可以省略override关键字
  • 抽象类可以覆写val和var字段
  • 抽象类的子类要么是抽象类,要么重写父类中的所有抽象方法或字段

或者:

abstract class Animal {
    var name:String
    var age:Int = _
    val size:Int
}

Dog(var name:String,val size:Int) extends Animal()

trait 特质

  • 特质 (Traits) 用于在类 (Class)之间共享程序接口(Interface)和字段 (Fields)。 它们类似于Java 8的接口
  • 类和对象 (Objects)可以扩展特质,但是特质不能被实例化,因此特质没有参数。
  • 最简化的特质就是关键字trait+标识符
  • 使用 extends 关键字来扩展特征。然后使用override 关键字来实现trait里面的任何抽象成员

注意:如果class A 需要继承class B ,继承特质T1,T2,那 么书写格式就是:

//当某个特质被用于组合类时,被称为混入(mixin)。
class A extends B with T1 with T2 {
	//覆写抽象的内容
}
动态混入

就是在创建对象的时候混入特质

动态混入进一步对代码解耦

def main(args: Array[String]): Unit = {
    //动态混入
    val demo = new Demo with T1 with T2{
        override def m01: Unit = {
        }
        override var num: Int = _
    }
}

注意:Java中的接口在scala中可以直接当作特质使用

访问控制

  • Scala中没有public。默认就是public
  • private修饰的只能本类及伴生对象中使用
  • protected的访问权限比Java还小,只能在子类中访问。

package包

  • 一个scala源文件中可以有多个package
  • package中可以有子package
  • 一个package中可以定义类、特质,object,不能定义 方法和字段
包对象 package object
  • 包对象中可以定义任何内容,而不仅仅是变量和方法。 例如,包对象经常用于保存包级作用域的类型别名和隐式转换。
  • 包对象甚至可以继承 Scala 的类和特质。
  • 每个包都允许有一个包对象。 在包对象中的任何定义都被认为是包自身的成员。
package object fruits extends FruitAliases with FruitHelpers {
	// helpers and variables follows here
}
导包
  • 使用import导包
  • Scala中import可以在任意位置
  • 导包可以使用选择器{}选择想要的内容
import com.bigdata.demo01.{A, Demo}
  • 导入包下所有的内容,使用_

    // _相当于Java中的*
    import com.bigdata.demo01._
    
  • 导包的时候,取别名

    // Demo => JavaDemo 给Demo取别名为JavaDemo
    import com.bigdata.demo01.{ A , Demo => JavaDemo}
    object Demo02 {
        def main(args: Array[String]): Unit = {
            val a = new A()
            val demo = new JavaDemo()
        }
    }
    
哪些不需要导包:
  1. java.lang
  2. scala包下的内容不需要导包;但是scala包的子包的内容需要导包
  3. scala.Predef 下的内容不需要导包
包的可见性

private[包名] : 当前包及其子包可见

package com.bigdata.demo03
package a{
}

package object a{
    //表示num可以在com及其子包可见
    private[com] val num = 10
}

object PrivateDemo {
    def main(args: Array[String]): Unit ={
    	println(a.num)
    }
}

异常

scala中只有运行时异常,没有编译异常

scala使用的是java的异常。

  • 捕获异常

    try {
        val num = 10 / 0
        println(num)
    }catch {
        //匹配异常
        case e:ArithmeticException => println("bbbbb")
        case e:Exception => println("aaaaa")
    }finally {
    	println("finally-------------")
    }
    
  • @throws

    //throws注解用来表示该方法会产生什么类型的异常,异常的原因是什么
    @throws[ArithmeticException]("除数不能为0")
    def m01(): Unit ={
        val num = 10 / 0
        println(num)
    }
    
自定义异常
  1. 继承RuntimeException

    class AgeException(msg:String) extends RuntimeException(msg){
    }
    
  2. 抛出异常

    def m01(age:Int): Unit ={
        if(age < 18){
        	throw new AgeException("age不能小于18")
        }else{
        	println(age)
        }
    }
    

apply方法

package com.bigdata.demo04
class Worker {
}

object Worker{
def apply(): Worker = new Worker()
}

object WorkerDemo{
    def main(args: Array[String]): Unit ={
        //省略new之后调用的就是伴生对象中的apply
        /**
        * val worker = Worker
        * worker的类型是com.bigdata.demo04.Worker$
        * 分析:
        * 此时=后面的Worker没有使用new,那就说明Worker不是类而是对象
        * 所以此时val worker指向的是伴生对象Worker
        *
        * val worker = Worker()
        * Worker带上()后就是调用apply方法
        * 但是我们需要的worker的类型是com.bigdata.demo04.Worker
        */
        val worker = Worker()
        println(worker)
    }
}

样例类

  • 样例类(Case classes)和普通类差不多,只有几点关键差别。
  • 样例类非常适合用于不可变的数据。
  • 一个最简单的案例类定义由关键字case class,类名,参数列表(可为空)组成:
case class Book(isbn: String)

在声明样例类时,下面的过程自动发生了:

  • 构造器的每个参数都成为val,除非显式被声明为var,但是并不推荐这么做;
  • 在伴生对象中提供了apply方法,所以可以不使用new关键字就可构建对象;
  • 提供unapply方法使模式匹配可以工作;
  • 生成toString、equals、hashCode和copy方法,除非显示给出这些方法的定义。
  • 样例类在比较的时候是按值比较而非按引用比较:

你可以通过copy方法创建一个案例类实例的浅拷贝,同时可以指定构造参数来做一些改变。

所以在实际应用中,样例类可以用做实体类、还可以用在模式匹配中

隐式转换

隐式转换在两种情况下会用到:

  • 如果一个表达式 e 的类型为 S, 并且类型 S 不符合表达式的期望类型 T。
  • 在一个类型为 S 的实例对象 e 中调用 e.m, 如果被调用的 m 并没有在类型 S 中声明
隐式方法

就是在方法前加上implicit

package com.bigdata.demo05
object ImplicttTool {
    implicit def xxxxx(d:Double):Int={
        d.toInt
    }
}
package com.bigdata.demo05
object ImplicitDemo {
    def main(args: Array[String]): Unit ={
        //显式转换
        // val a:Int = 3.14.toInt
        //隐式转换
        //如果一个表达式 e 的类型为 S, 并且类型S 不符合表达式的期望类型 T。
        import ImplicttTool.xxxxx
        val a:Int = 3.14 //val a:Int = xxxxx(3.14)
        val b:Int = 2.11
        val c:Int = 13.11
        println(s"$a,$b,$c")
        //隐式转换
        /**
        * 隐式转换:可以帮我们将Double转成Int
        *
        * 将Double转成Int这是一个功能,所以可以定义一个方法来完成
        * 个方要完成隐式转换的功能,那么这个方法必须是隐式方法
        *
        * 隐式方法给方法名无关,只跟参数和返回值有关
        * 在一个作用域中不能找到多个可以引用的隐式方法,这样会出错的
        *
        * 隐式转换定义在object中
        */
    }
}
隐式类

隐式类可以给一个已存在的类进行扩展方法和属性

package com.bigdata.demo05
object ImplicitDemo01 {
    def main(args: Array[String]): Unit =
    {
        val num:Int = 10
        //在一个类型为 S 的实例对象 e 中调用e.m, 如果被调用的 m 并没有在类型 S 中声明
        println(num ++)// DDDD(num) ++
        println(num --)
    }
    
    //隐式类必须有一个带参的主构造
    //你要给哪一个类做扩展,哪一个类就是参数
    //隐式类跟类名无关
    implicit class DDDD(var i:Int){
        //定义你要需要扩展的方法
        def ++ ():Int={
            i = i + 1
            i
        }
        def -- ():Int={
            i = i - 1
            i
        }
    }
}
隐式参数

方法可以具有 隐式 参数列表,由参数列表开头的 implicit 关键字标记。

如果参数列表中的参数没有像往 常一样传递, Scala 将查看它是否可以获得正确类型的 隐式值,如果可以,则自动传递。

隐式值

隐式值就是给隐式参数使用的

优先级:

显示赋值 > 隐式值 > 默认值

object ImplicitDemo {
    def main(args: Array[String]): Unit =
    {
        implicit val a = 10
        m01(1)
    }
    
    def m01(implicit a:Int = 20)={
    	println(a)
    }
}
//a和b都是隐式参数
def m01(implicit a:Int,b:Int)={
    println(a + b)
}

如果要指定参数列表中的某些参数为隐式 (implicit),应该使用多参数列表。例如:

/**
* 当多个参数中部分参数是隐式参数的时候
* 这个参数必须是多参数列表
* 一个()就是一个参数列表
* 隐式参数列表要放在后面
* @param a
*/
def m01(a:Int)(implicit b:Int)={
    println(a + b)
}

def main(args: Array[String]): Unit = {
    implicit val a = 10
    m01(2)
    m01(2)(3)
}
隐式对象

object前加上implicit。其实隐式对象也是隐式值。

trait T1{
    def show
}

object ImplicitDemo01 {
    def main(args: Array[String]): Unit =
    {
        implicit object TT extends T1{
            override def show: Unit = {
                println("tt--------")
            }
        }
        m01
    }
    
    def m01(implicit t:T1): Unit ={
        t.show
    }
}

高阶函数

高阶函数是指使用其他函数作为参数、或者返回一个函 数作为结果的函数。在Scala中函数是“一等公民”,所以 允许定义高阶函数。这里的术语可能有点让人困惑,我 们约定,使用函数值作为参数,或者返回值为函数值的 “函数”和“方法”,均称之为“高阶函数” 。

闭包

  • 闭包是一个函数,返回值依赖于声明在函数外部的一个或多个变量。
  • 闭包通常来讲可以简单的认为是可以访问一个函数里面局部变量的另外一个函数。
def m01(x:Int) ={
    //闭包
    //函数 -- 对象
    //因为x要被内部的函数f访问,所以默认为val
    val f = (a:Int) => a + x
    f
}

多参数列表(柯里化) currying

方法可以定义多个参数列表,当使用较少的参数列表调用多参数列表的方法时,会产生一个新的函数,该函数接收剩余的参数列表作为其参数。这被称为柯里化

object CurryDemo {
    def main(args: Array[String]): Unit =
    {
        println(m01(1)(2)(3))//柯里化
        // val f: Int => Int = m02(2)
        //
        // val i: Int = f(3)
        // println(i)
        println(m02(2)(3,4))
        println(m03(2)(3)(4))
        println(m04(2,3)(4))
        println(m00(1)(2))
    }
    
    def m00(a:Int)(b:Int) = {
        a + b
    }
    
    def m01(a:Int)(b:Int)(c:Int) = {
        a + b + c
    }
    
    def m02(a:Int)= (b:Int,c:Int)=> a + b + c
    def m03(a:Int)(b:Int)= (c:Int)=> a + b + c
    def m04(a:Int,b:Int)= (c:Int)=> a + b + c
}

递归函数

/**
* 递归:方法体中调用方法自身
*
* 1、定义方法
* 2、结束条件
* 3、找规律
*/
object FactorialDemo {
    def main(args: Array[String]): Unit =
    {
        println(factorial(5))
    }
    
    //1、定义方法
    def factorial(n:Int):Long={
        if(n < 0){
            throw new RuntimeException("负数没有阶乘")
        }
        //2、结束条件
        if(n == 1 || n == 0){
            1
        }else{
            //3、找规律
            n * factorial(n - 1)
        }
    }
}

部分(偏)应用函数

当我们调用一个函数的时候,只使用了该函数的部分参 数,此时会返回一个新的函数,这个新的函数就是原来 函数的部分(偏)应用函数。

package com.bigdata.demo
object FunctionDemo {
    def main(args: Array[String]): Unit =
    {
        m01(1,10)
        m01(2,10)
        m01(3,10)
        
        //f就是m01的部分引用函数
        val f: Int => Unit = m01(_,10)
        f(1)
        f(2)
        f(3)
    }
    
    def m01(a:Int,b:Int) = {
        println(a + b)
    }
}

偏函数

偏函数不是一个函数,而是一个特质PartialFunction

package com.bigdata.demo

object FunctionDemo02 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,"java")

    val p: PartialFunction[Any, Int]  = new PartialFunction[Any, Int] {
      /**
       * 判断是不是数字,true就会调用apply
       */
      override def isDefinedAt(x: Any): Boolean = {
        x.isInstanceOf[Int]
      }

      override def apply(v1: Any): Int = {
        v1.asInstanceOf[Int] * 2
      }
    }

    println(list.collect(p))

  }
}
package com.bigdata.demo

object FunctionDemo03 {

  def main(args: Array[String]): Unit = {
    val list = List(1,2,3,"java")

//    println(list.collect(m01()))
    println(list.collect({case num:Int => num * 2}))

  }

  /**
   * 如果一个{}中只有case语句,那么这个
   * {case ...}就是一个匿名函数
   * 这是这个匿名函数有点特殊,可以转成偏函数
   */
  def m01():PartialFunction[Any,Int] = {
    case num:Int => num * 2
  }

}
package com.bigdata.demo

object FunctionDemo04 {

  def main(args: Array[String]): Unit = {

    println(m01(3, _ * 2))
    //{case ...}作为匿名函数
    println(m01(3, {case a:Int => a * 2}))
  }

  def m01(num:Int,f:Int=>Int) = {
    f(num)
  }

}

传值调用和传名调用

  • 传值调用:先求值再传递
  • 传名参数:仅在被使用时触发实际参数的求值运算。 先传递再求值。与 传值参数 正好相反。

要将一个参数变为传名参数,只需在它的类型前加上=>。

package com.bigdata.demo01
object ByNameAndValueDemo {
    def main(args: Array[String]): Unit =
    {
        // byValue(
        // println("java-----")
        // )
        byName(
            println("java-----")
        )
    }
    
    /**
    * java-----
    * start-------------
    * ()
    * end------------
    * 传值调用:先求值再传递
    * 所以这里的code接收到的是()
    */
    def byValue(code:Unit)={
        println("start-------------")
        println(code)
        println("end------------")
    }
    
    /**
    * start-------------
    * java-----
    * end------------
    * 传名参数:先传递再求值
    * code接收到的是 println("java-----")
    */
    def byName(code: =>Unit)={
        println("start-------------")
        code //println("java-----")
        println("end------------")
    }
}

元组 Tuple

  • 在 Scala 中,元组是一个可以容纳不同类型元素的类。
  • 元组是不可变的。
  • 当我们需要从函数返回多个值时,元组会派上用场。
  • Scala 中的元组包含一系列类:Tuple2,Tuple3等,直到 Tuple22。 因此,当我们创建一个包含 n 个元素(n位于 2 和 22 之间)的元组时,Scala 基本上就是从上述的一组类中实例化 一个相对应的类,使用组成元素的类型进行参数化。 上例中,ingredient 的类型为Tuple2[String, Int]。
  • 元组使用(n1,n2…)表示
  • Tuple2可以叫做对偶元组,使用(n1,n2)或者 n1 -> n2

访问元素

使用下划线语法来访问元组中的元素。 ‘tuple._n’ 取出 了第 n 个元素(假设有足够多元素)。

package com.bigdata.demo01
object TupleDemo {
    def main(args: Array[String]): Unit =
    {
        val tuple: (Int, Int) = m01(1, 2)
        // 访问元组的元素
        println(tuple._1)
        println(tuple._2)
    }
    
    def m01(a:Int,b:Int)={
        // new Tuple2[Int,Int](a+b,a-b)
        (a+b,a-b)
        (a+b) -> (a-b)
    }
}

解构元组数据

Scala 元组也支持解构。

val (name, age) = ("zhangsan",20)
println(name)
println(age)

集合 Collection

Scala中的集合分为:可变集合(mutable)和不可变集合(immutable)

Scala集合系统地区分了可变集合和不可变集合。可变集合可以就地更新或扩展。这意味着,作为副作用,您可以更改、添加或删除集合的元素。相比之下,不可变集合永远不会改变。您仍然有模拟添加、删除或更新的操作,但这些操作在每种情况下都将返回一个新的集合,并保持旧的集合不变。

  • 可变集合:更改、添加或删除集合的元素,得到还是 原来的集合
  • 不可变集合:更改、添加或删除集合的元素返回一个 新的集合,并保持旧的集合不变。

下图显示了scala.collection包中的所有集合

在这里插入图片描述

下图显示了scala.collection.immutable包中的所有集合:

在这里插入图片描述

下图显示了scala.collection.mutable包中的所有集合:

在这里插入图片描述

数组 Array

Array是不可变的数组

数组在Scala中是一种特殊的集合。一方面,Scala数组 与Java数组一一对应。也就是说,Scala数组Array [Int] 表示为Java Int[],数组[Double]表示为Java Double[], 数组[String]表示为Java字符串[]。

但与此同时,Scala数组提供的功能比它们的Java类似程 序多得多。首先,Scala数组可以是通用的。也就是说, 您可以有一个数组[T],其中T是类型参数或抽象类型。 其次,Scala数组与Scala序列兼容——你可以在需要 Seq[T]的地方传递一个数组[T]。最后,Scala数组还支持 所有的序列操作。

def main(args: Array[String]): Unit = {
    // 3是长度
    val arr = new Array[Int](3)
    //通过下标访问元素
    arr(0) = 10
    arr(1) = 11
    println(arr(0))
    println(arr(1))
    println(arr(2))
}
def main(args: Array[String]): Unit = {
    // 1,2,3是数组元素
    val arr = Array[Int](1,2,3)
    println(arr(0))
    println(arr(1))
    println(arr(2))
}

遍历数组

object ArrayDemo02 {
    def main(args: Array[String]): Unit =
    {
        // 1,2,3是数组元素
        val arr = Array[Int](1,2,3)
        //遍历数组的元素
        for(ele <- arr){
            println(ele)
        }
        println("-------------------------")
        
        //通过索引遍历元素
        for(index <- 0 until arr.length){
            println(arr(index))
        }
        println("-------------------------")
        
        //通过迭代器遍历数组
        val it: Iterator[Int] = arr.iterator
        while(it.hasNext){
            println(it.next())
        }
        println("===========================")
        
        // arr.foreach(m01)
        //
        arr.foreach((num:Int)=>println(num))
        // arr.foreach(num=>println(num))
        // arr.foreach(println(_))
        //终极方案
        arr.foreach(println)
    }
    
    def m01(num:Int):Unit={
        println(num)
    }
}

数组添加元素

package com.bigdata.demo01
object ArrayDemo03 {
    def main(args: Array[String]): Unit =
    {
        // 1,2,3是数组元素
        val arr = Array[Int](1, 2, 3)
        //+: 和 :+都是Array的方法
        //所以使用点语法就必须是Array对象.方法
        // val ints: Array[Int] = arr.+:(4)
        //将元素添加到数组的头部 :朝向数组的方向
        // val ints: Array[Int] = 4 +: arr
        将元素添加到数组的末尾
        val ints: Array[Int] = arr :+ 4
        println(arr.mkString(","))
        println(ints.mkString(","))
    }
}

可变数组 ArrayBuffer

def main(args: Array[String]): Unit = {
    val arr = new ArrayBuffer[Int]()
    //就是旧的数组中直接添加元素,不会返回新的数组
    arr.append(1,2,3)
    println(arr(0))
    println(arr(1))
    println(arr(2))
    arr.remove(1)
    println(arr)
    arr.foreach(println)
    println("----------------------")
    
    //:+ 返回依然是新的数组
    val ints: ArrayBuffer[Int] = arr :+ 4
    arr.foreach(println)
    ints.foreach(println)
}

二维数组 – 了解

package com.bigdata.demo01
object ArrayDemo05 {
    def main(args: Array[String]): Unit =
    {
        //2: 二维数组的长度
        //3: 一维数组的长度
        //二维数组:行和列
        val arr = Array.ofDim[Int](2,3)
        // println(arr(0).length)
        // arr.foreach(x=>{
        // x.foreach(println(_))
        // })
        arr.foreach(_.foreach(println(_)))
    }
}

List

:: 和 :::

val list = List(11,12,13)
/**
* :: 将单个元素添加到集合
* ::: 将集合中的元素添加到一个集合中
*/
val list02 = 1 :: 2 :: list ::: 3 :: 4 :: 5 :: Nil
println(list02)

:+ 和 :++

val list01 = List(1,2,3)
val list02 = List(11,12,13)
//单个元素和集合
// val ints: List[Int] = list01 :+ 10
//集合与集合
val ints: List[Int] = list02 ++: list01
println(ints)

map 和 filter

package com.bigdata.demo01
object ListDemo02 {
    def main(args: Array[String]): Unit =
    {
        val list = List(1,2,3)
        // println(list.collect({ case a: Int => a * 2 }))
        // println(list.map(a => a * 2))
        // println(list.map(_ * 2))
        /**
        * map是一个元素执行一次 一对一的
        */
        val ints: List[Int] = list.map(x =>
                                       {
                                           println("map----------------")
                                           x * 2
                                       })
        val ints1 = list.filter(_ % 2 == 0)
        println(ints1)
    }
}

++

def main(args: Array[String]): Unit = {
    val list01 = List(1,2,3,4)
    val list02 = List(11,12,13,14)
    // val ints: List[Int] = list01 ++ list02
    // val ints: List[Int] = list01.++(list02)
    //++:与++的区别是: ++:是从右到左
    // val ints: List[Int] = list01.++:(list02)
    val ints: List[Int] = list01 ++: list02
    println(ints)
}

flatten

def main(args: Array[String]): Unit = {
    val list = List(List(1,2,3),List(11,12,13))
    //List(1,2,3,11,12,13)
    val list01: List[Int] = list.flatten
    //压平
    println(list01)
}

flatMap

def main(args: Array[String]): Unit = {
    val list = List(List(1,2,3),List(11,12,13))
    //flatMap 一对多的 先map再flatten
    val ints: List[Int] = list.flatMap(_.map(_ * 2))
    println(ints)
}

head、排序等方法

def main(args: Array[String]): Unit = {
    val list = List(1,3,7,4,2)
    println(list.head)
    println(list.last)
    println(list.tail.tail.tail)//除了head就是tail
    println(list.take(2))//Top2
    println(list.sum)
    // println(list.sortBy(x => x))//升序
    println(list.sortBy(_ * 1))//升序
    // println(list.sortBy(x => -x))//降序
    println(list.sortBy(_ * -1))//降序
}

reduceLeft / reduce

package com.bigdata.demo
object ListDemo04 {
    def main(args: Array[String]): Unit =
    {
        val list = List(1,2,3,4,5,6)
        /**
        * a=1,b=2
        * a=3,b=3
        * a=6,b=4
        * a=10,b=5
        * a=15,b=6
        */
        val f =(a:Int,b:Int) =>{
            println(s"a=$a,b=$b")
            a + b
        }
        // val sum: Int = list.reduceLeft(f)
        // val sum: Int = list.reduceLeft((a:Int,b:Int) => a + b)
        // val sum: Int = list.reduceLeft((a,b) => a + b)
        // val sum: Int = list.reduceLeft(_+_)
        val sum: Int = list.reduceLeft(_ - _)
        println(sum)
    }
}
def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4,5,6)
    val f = (a:Int,b:Int) => {
        if(a > b){
            a
        }else{
            b
        }
    }
    val max = list.reduceLeft(f)
    println(max)
}

reduceRight

def main(args: Array[String]): Unit = {
    val list = List(1,2,3,4,5,6)
    /**
    * a=5,b=6
    * a=4,b=-1
    * a=3,b=5
    * a=2,b=-2
    * a=1,b=4
    */
    val f =(a:Int,b:Int) =>{
        println(s"a=$a,b=$b")
        a - b
    }
    val sum: Int = list.reduceRight(f)
    println(sum)
}

foldLeft

object ListDemo07 {
    def main(args: Array[String]): Unit =
    {
        val list = List(1,2,3,4,5,6)
        /**
        * a=10,b=1
        * a=11,b=2
        * a=13,b=3
        * a=16,b=4
        * a=20,b=5
        * a=25,b=6
        */
        val f = (a:Int,b:Int)=>{
            println(s"a=$a,b=$b")
            a + b
        }
        
        // val res: Int = list.foldLeft(10)(f)
        /**
        * a=6,b=10
        * a=5,b=-4
        * a=4,b=9
        * a=3,b=-5
        * a=2,b=8
        * a=1,b=-6
        */
        val f01 = (a:Int,b:Int)=>{
            println(s"a=$a,b=$b")
            a - b
        }
        
        // val res: Int = list.foldRight(10)(f01)
        //def fold[A1 >: A](z: A1)(op: (A1,A1) => A1): A1 = foldLeft(z)(op)
        // list.fold()
        // def /:[B](z: B)(op: (B, A) => B): B = foldLeft(z)(op)
        // def :\[B](z: B)(op: (A, B) => B): B = foldRight(z)(op)
        // /: = foldLeft
        val res: Int = list./:(10)(f)
        println(res)
    }
}

并集、交集、差集、拉链

package com.bigdata.demo
object ListDemo08 {
    def main(args: Array[String]): Unit =
    {
        val list01 = List(1,2,3,4,5,6)
        val list02 = List(1,3,5,7,9,11,12)
        //并集
        val ints: List[Int] = list01.union(list02)
        println(ints)
        
        //交集
        val ints1: List[Int] = list01.intersect(list02)
        println(ints1)
        
        //差集
        val ints2: List[Int] = list01.diff(list02)
        println(ints2)
        
        //拉链
        val tuples: List[(Int, Int)] = list01.zip(list02)
        println(tuples)
    }
}

sliding

def main(args: Array[String]): Unit = {
    val list01 = List(1,2,3,4,5,6)
    //第一个参数:窗口大小
    //第二个参数:窗口滑动步长
    val iterator: Iterator[List[Int]] = list01.sliding(2,2)
    iterator.foreach(println)
}

单词计数

package com.bigdata.demo
object ListDemo12 {
    def main(args: Array[String]): Unit =
    {
        val list = List("welcome to chengdu","chengdu ni hao")
        
        list.flatMap(_.split("\\s+"))
        .map((_, 1))
        .groupBy(_._1)
        .map(t => (t._1, t._2.size))
        .foreach(println)
        println("------------------------")
        
        list.flatMap(_.split("\\s+"))
        .groupBy(x => x)
        .map(t=>(t._1,t._2.size))
        .foreach(println)
        println("------------------------")
        
        list.flatMap(_.split("\\s+"))
        .groupBy(x => x)
        .mapValues(_.size)
        .foreach(println)
    }
}

元组排序

object ListBufferDemo02 {
    def main(args: Array[String]): Unit =
    {
        val list = ListBuffer[(String,String)](("name","zhangsan"),("name","lisi"),("age","22"),("age","18"))
        // val list = ListBuffer[(String,String)]("name"->"zhangsan","name"->"lisi","age"->"22","age"->"18")
        //元组的排序:先按照第一个排序,再按照第二个排序
        val tuples: ListBuffer[(String,String)] = list.sortBy(t => t)
        println(tuples)
    }
}

Map

package com.bigdata.demo01
import scala.collection.immutable.HashMap
object MapDemo {
    def main(args: Array[String]): Unit =
    {
        // val map = new HashMap[String,String]()
        //
        // val map1: HashMap[String, String] = map.+("name" -> "zhangsan")
        //
        // println(map1)
        // println(map)
        val map = HashMap[String,Int]("a"->1,"b"->2,"c"->3)
        val keys: Iterable[String] = map.keys
        keys.foreach(key=>{
            println(map.get(key).getOrElse(0))
            println(map(key))
        })
        println("-------------------------")
        
        for((k,v) <- map){
            println(k)
        }
    }
}

模式匹配

匹配变量

作用:接收所有的结果

def main(args: Array[String]): Unit = {
    val num = 10
    val a = 10
    val b = 20
    num match {
        //这里的_和a表示的是接收num的所有值
        //这里使用_还是变量名,取决于=>后面是否需要使用该变量
        //需要使用就用变量名;不需要使用就用_
        case _ => println("20")
        //case a 这个语句是废话,因为永远执行不了
        //这里的a和前面定义的var a 不是同一个
        case a => println("10" + a)
    }
}

匹配常量

def main(args: Array[String]): Unit = {
    val num = 100
    val Max = 100
    num match {
        //匹配常量,首字母必须大写
        case Max => println("max== " + 100)
        case _ => println("no match")
    }

匹配元素(值)

object MatchDemo03 {
    def main(args: Array[String]): Unit =
    {
        val listData = List(List(1,2,3),List(1,3,5),List(11,2,4,5))
        listData.foreach(list=>{
            list match {
                // case 1::2::3::Nil => println("1,2,3")
                // case List(1,2,3) => println("1,2,3")
                // case List(_,_,_) => println("size = 3")
                //if 模式匹配守卫
                // case a if a.length == 3 => println("size = 3")
                // case _ if list.length == 3 => println("size = 3")
                // case _ if list.head == 1 => println("head = 1")
                //_*,表示剩下的所有元素
                // case List(1,_*) => println("head = 1")
                //a@_* 表示将_*的值绑定在a上
                case List(1,2,a@_*) => println(a)
                case _ => println("no match")
            }
        })
    }
}

匹配自定义对象

package com.bigdata.demo02
case class Cat( name:String, age:Int)
//class Cat(val name:String,val age:Int)
//
//object Cat{
//
// def apply(name: String, age: Int): Cat = new Cat(name, age)
//
// def unapply(cat: Cat): Option[(String, Int)] = {
// Some(cat.name,cat.age)
// }
//}

object MatchDemo04 {
    def main(args: Array[String]): Unit =
    {
        val cat = Cat("花猫", 1)
        cat match {
            /**
            * 模式匹配必须有unapply
            * unapply返回None:匹配失败
            * unapply返回Some且属性相同:匹配成功
            */
            case Cat("花猫", 1) => println("cat--------------")
            case _ => println("no match!")
        }
    }
}

匹配类型

def main(args: Array[String]): Unit = {
    val num:Any = "10"
    num match {
        case _:Int => println("int")
        case _:String => println("String")
        case _ => println("no match")
    }
}

匹配集合元素的类型/泛型

Scala中的Array[T]是可以匹配T的类型的。因为编译 Array的时候转成了Java的数组。Java的数组是没有泛型 的。也就是Array[Int]转成了Java的int[]。

object MatchDemo06 {
    def main(args: Array[String]): Unit =
    {
        //泛型编译后就被擦除了
        val list = List(1,2,3,4)
        listMatch(list)
    }
    
    //Manifest[T] 可以理解成Manifest保存了T的信息
    def listMatch[T](list:List[T])(implicit m:Manifest[T]) ={
        list match {
            case _ if m == manifest[Int] => println("int----")
            case _ if m == manifest[String] => println("String----")
            case _ => println("no match!")
        }
    }
}

提取器对象

  • 提取器对象是一个包含有 unapply 方法的单例对象。
  • apply 方法就像一个构造器,接受参数然后创建一个实例对象,反之 unapply 方法接受一个实例对象然后返回最初创建它所用的参数。
  • 提取器常用在模式匹配和偏函数中

泛型

协变、逆变、不变 – 了解

Java的泛型只支持不变

假设有元素类型A和B,A是B的父类

  • 不变:List[A]和List[B]没有父子关系

    package com.bigdata.demo02
    class A
    class B extends A
    
    //不变
    class MyList[T]
    
    object GenericsDemo01 {
        def main(args: Array[String]): Unit = {
            var listA = new MyList[A]
            var listB = new MyList[B]
            listA = listB//error
        }
    }
    
  • 协变:List[A]和List[B]有父子关系 参数类型

    package com.bigdata.demo02
    class A
    class B extends A
    //协变
    class MyList[+T]
    
    object GenericsDemo01 {
        def main(args: Array[String]): Unit =
        {
            var listA = new MyList[A]
            var listB = new MyList[B]
            listA = listB
        }
    }
    
  • 逆变: List[B]是List[A]父类 返回值类型

    package com.bigdata.demo02
    class A
    class B extends A
    //逆变
    class MyList[-T]
    
    object GenericsDemo01 {
        def main(args: Array[String]): Unit =
        {
            var listA = new MyList[A]
            var listB = new MyList[B]
            listB = listA
        }
    }
    

泛型上限和下限

  • 上限:T <:A

    表示T只能是A及其A的子类

    package com.bigdata.demo02
    /**
    * 定义一个方法,比较两个数的大小,返回较大的值
    */
    object GenericsDemo02 {
        def main(args: Array[String]): Unit =
        {
            val i = 10
            val j = 11
            val max = compare(new Integer(i), new Integer(j))
            println(max)
        }
        
        /**
        * 上限 <:
        */
        def compare[T <: Comparable[T]](a:T,b:T): T ={
            if(a.compareTo(b) > 0){
                a
            }else{
                b
            }
        }
    }
    
  • 下限 T >: A

    package com.bigdata.demo02
    class AA
    class BB extends AA
    class CC extends BB
    class DD
    
    object GenericsDemo03 {
        def main(args: Array[String]): Unit =
        {
            m01(new AA)
            m01(new BB)
            m01(new CC)
            m01(new DD)
        }
        
        //>: 下限 跟Java不一样,可以是任意数据
        def m01[T >: BB](a:T)={
            println(a)
        }
    }
    

泛型的视图界定

<% 视图界定,视图界定 会触发隐式转换

package com.bigdata.demo02
/**
* 定义一个方法,比较两个数的大小,返回较大的值
*/
object GenericsDemo04 {
    def main(args: Array[String]): Unit =
    {
        val i = 10
        val j = 11
        val max = compare(i, j)
        println(max)
    }
    //<% 视图界定
    //视图界定 会触发隐式转换
    /*
    trait IntOrdering extends Ordering[Int] {
        def compare(x: Int, y: Int) = java.lang.Integer.compare(x, y)
    }
    implicit object Int extends IntOrdering
    implicit def orderingToOrdered[T](x: T)(implicit ord: Ordering[T]):Ordered[T] = new Ordered[T] { 
    	def compare(that:T): Int = ord.compare(x, that) 
    }
    */
    def compare[T <% Ordered[T]](a:T,b:T):T ={
        if (a > b) a else b
    }
}

泛型的上下文界定

T : Ordering 上下文界定 上下文界定 也需要隐式转换

package com.bigdata.demo02
/**
* 定义一个方法,比较两个数的大小,返回较大的值
*/
object GenericsDemo05 {
    def main(args: Array[String]): Unit =
    {
        val i = 10
        val j = 11
        // val max = compare(i, j)
        val max = compare01(i, j)
        println(max)
    }
    
    def compare[T](a:T,b:T)(implicit o:Ordering[T]): T ={
        if(o.gt(a,b)) a else b
    }
    
    //T : Ordering 上下文界定
    //上下文界定 也需要隐式转换
    def compare01[T : Ordering](a:T,b:T): T ={
        //招魂
        val o: Ordering[T] = implicitly(Ordering[T])
        if(o.gt(a,b)) a else b
    }
}

隐式转换的查找

  1. 本类的作用域中查找
  2. 相关类中查找
  3. 在Predef中查找
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值