Scala05

伴生对象 vs 伴生类

Scala中的伴生对象
对于Object内部的方法,我们可以直接通过Object.method(对象名.方法)来调用
类似于Java中的static
举例:现在object里面有个increment方法

object Timer {
  var count = 0

  def increment():Long = {
    count += 1
    count
  }
}

在scala的shell里运行:

scala> object Timer {
     |   var count = 0
     |   def increment():Long = {
     |     count += 1
     |     count
     |   }
     | }
defined object Timer

scala> Timer.increment
res33: Long = 1

scala> Timer.increment
res34: Long = 2

scala> Timer.increment
res35: Long = 3

伴生对象 和伴生类 是相辅相成的
class A
object A
class A 叫做object A 的伴生类
object A 叫做class A 的伴生对象

object ApplyDemo {
  def main(args: Array[String]): Unit = {
    for(i <- 1 to 10){
      ApplyTest.increment
    }
    println(ApplyTest.count)
  }
}
class ApplyTest{

}
object ApplyTest{
  println("object ApplyTest enter...")
  var count = 0

  def increment = {
    count = count + 1
    count
  }

  println("object ApplyTest leave...")
}

输出结果:

object ApplyTest enter...
object ApplyTest leave...
10

Process finished with exit code 0

从上面可以看出,你调用object里的方法,会触发它把object里所有的东西先执行一遍,方法不调用不执行(increment 只是定义了,没有调用),在for里面触发了,每次把它加1,所以看到的是先打印两句话,然后把count打印出来。
有点想不明白,for循环里循环10次,不应该触发10次object的方法吗,为什么不把那两句话打印10次?

上面代码变一下:

object ApplyDemo {
  def main(args: Array[String]): Unit = {
    ApplyTest.static
  }
}

object ApplyTest{
  println("object ApplyTest enter...")
  
def static: Unit = {
    println("object ApplyTest static")
  }

  println("object ApplyTest leave...")
}

输出结果:

object ApplyTest enter...
object ApplyTest leave...
object ApplyTest static

Process finished with exit code 0

调用object.static方法,触发object里所有东西执行一遍,方法不调用不执行,先打印object里的两句话,然后,运行那个static方法,有了第三行。
再升级:

package com.ruozedata.bigdata.scala04
object ApplyDemo {
  def main(args: Array[String]): Unit = {
    val a = new ApplyTest()    //new 一个 ApplyTest这个类  类要用的时候先new出来
    println(a)       //这个println其实调用的是toString方法,包名+类名@hashcode
  }
}

class ApplyTest{
}

object ApplyTest{
  println("object ApplyTest enter...")

  def static: Unit = {
    println("object ApplyTest static")
  }

  println("object ApplyTest leave...")
}

输出结果:

//因为调用的是toString方法,就是包名+类名@hashcode   所以是下面的:
com.ruozedata.bigdata.scala04.ApplyTest@1b604f19

Process finished with exit code 0

再变一下:

package com.ruozedata.bigdata.scala04

object ApplyDemo {
  def main(args: Array[String]): Unit = {
    val a = new ApplyTest()
    println(a)
    a.method()    //调用a里的method方法
  }
}
class ApplyTest{
  def method(): Unit ={
    println("class ApplyTest method")
  }
}
object ApplyTest{
  println("object ApplyTest enter...")
  def static: Unit = {
    println("object ApplyTest static")
  }

输出结果:

com.ruozedata.bigdata.scala04.ApplyTest@1b604f19
class ApplyTest method

Process finished with exit code 0

再扩展一下,下面这个很重要

package com.ruozedata.bigdata.scala04

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

	//平时我们都是new的
    //现在没有new,直接=类名()   其实调用的是object对象里面的apply方法
    //apply方法被触发,触发之后再new出来
    val b = ApplyTest()  //没有new    
    b.method()
  }
}

class ApplyTest{
  def method(): Unit ={
    println("class ApplyTest method")
  }
  def apply() ={
    println("class apply method invoked...")
  }
}

object ApplyTest{
  println("object ApplyTest enter...")
  var count = 0

  def apply() ={           //apply它底层返回的是下面new出来的ApplyTest这个类
    println("object apply method invoked...")
    new ApplyTest()      //在这里new 一个ApplyTest类出来
  }

  println("object ApplyTest leave...")
}

输出结果:

object ApplyTest enter...
object ApplyTest leave...
object apply method invoked...
class ApplyTest method

Process finished with exit code 0

记住:
遇到 xxx = 类名() 一定是调用object对象里的apply方法,然后new出来

还有:

object ApplyDemo {
  def main(args: Array[String]): Unit = {
    val c = new ApplyTest()
    println( c )
    println(c())    //c是一个引用,c()调用的是Class的apply方法,不常用
  }
}
class ApplyTest{
  def method(): Unit ={
    println("class ApplyTest method")
  }
  def apply() ={
    println("class apply method invoked...")
  }
}


object ApplyTest{
  println("object ApplyTest enter...")

  def apply() ={  //apply它底层返回的是下面new出来的ApplyTest这个类
    println("object apply method invoked...")
    new ApplyTest()  //在这里new 一个ApplyTest类出来
  }

  println("object ApplyTest leave...")
}

输出结果:

com.ruozedata.bigdata.scala04.ApplyTest@1b604f19
class apply method invoked...

Process finished with exit code 0

记住两句话:
①遇到 xxx = 类名() 一定是调用object对象里的apply方法,然后new出来。(在apply里做了什么?new 一个,然后最后一行返回)
②如果是对象/引用(就是上面new出来的),它调用的是Class.apply方法
举例:
在创建一个数组的时候,
var array = Array(“a”,“b”,“c”)
点击Array,可以看到它调用的就是object对象里的apply方法
在这里插入图片描述

把一个函数赋给一个变量

object FunctionAdApp {
  def main(args: Array[String]): Unit = {
    val sayHelloFunc = sayHello _    //就是这样写的,空格加一个下划线
    println(sayHelloFunc("zhangsan"))
  }

  def sayHello(name:String)={
    println("hello : " + name)
  }
}

匿名函数

匿名函数(参数名:参数类型)=>函数体

 //定义了一个匿名函数,并把匿名函数赋值给了一个变量(也可以赋值给一个函数)
object FunctionNoNameApp {
  def main(args: Array[String]): Unit = {
    val add = (x:Int,y:Int) =>{  x+y  }
    println(add(2,3))
  }
}

函数的克里化currying

spark的udf函数里面经常会用到

object FunctionCurryingApp {
  def main(args: Array[String]): Unit = {
    println(sum(12,2))
    println(add(12)(2))    //调用
  }
  
  def sum(x:Int,y:Int)= x+y    //正常是这样的
  def add(x:Int)(y:Int)= x+y   // 函数的克里化currying
}

隐式转换

在面试scala的时候必问的题目。
隐式:偷偷摸摸的进行
目的:悄悄的为一个类的方法进行增强

目的:把一个Man悄悄的变为一个SuperMan
悄悄的为Man这个类增加一个方法,fly,让Man这个类会fly
举例:

object ImplicitApp {
  def main(args: Array[String]): Unit = {
    //定义隐式转换
    //入参是一个man,进去一个man,返回值是一个Superman,出来一个Superman
    implicit def man2superman(man:Man):SuperMan = new SuperMan(man.name)
    val man = new Man("xijinping")
    man.fly()   //man里面本来是没有的,隐式转换后就有fly方法了
  }
}

class Man(val name:String){
  def eat(): Unit ={
    println(s"$name can eat....")
  }
}
class SuperMan(val name:String){
  def fly(): Unit ={
    println(s"$name can fly....")
  }
}

输出结果:

xijinping can fly....

Process finished with exit code 0

再举个读文件增强的例子:

package com.ruozedata.bigdata.scala04
import java.io.File
import scala.io.Source

object ImplicitApp2 {
  def main(args: Array[String]): Unit = {
    implicit def file2RichFile(file:File):RichFile = new RichFile(file)

    val file = new File("E://output.txt")
    val content = file.read()
    println(content)
  }
}
class RichFile(val file:File){
  def read() = Source.fromFile(file.getPath).mkString
}

模式匹配

变量 match {
case 值1 => 代码
case 值2 => 代码
case _ =>代码
}

举例:

import scala.util.Random

object MatchApp {
  def main(args: Array[String]): Unit = {
    val regions =Array("anhui","shanghai","jiangsu","zhejiang")
    val region = regions(Random.nextInt(regions.length))   //获取一个随机数
    println(region)

    region match {
      case "anhui" => println("anhui")
      case "shanghai" => println("shanghai")
      case "jiangsu" => println("jiangsu")
      case _        => println("zhejiang")
    }
  }

上面工作中不怎么用,用的最多的还是在scala的异常处理里面。
比如在打开文件,去读取文件,涉及文件IO读取的时候,最好加上try catch。
try{
代码
}
catch{
case //异常处理匹配 这里用
case
case

}
finally{
比如关闭文件等操作
}
模式既可以匹配值,也可以匹配类型
类型比如说,异常的类型有哪些,看看能匹配到哪个类型。

偏函数 PartitialFunction

工作或面试用的比较多。
模式匹配也可以用偏函数来实现。
先看一下正常的模式匹配怎么写:

import scala.util.Random

object MatchApp {
  def main(args: Array[String]): Unit = {
    val regions =Array("anhui","shanghai","jiangsu","zhejiang")
    val region = regions(Random.nextInt(regions.length))
    println(region)
    person(region)

    def person(city:String)= city match {
      case "anhui" => println("anhui person")
      case "shanghai" => println("shanghai person")
      case "jiangsu" => println("jiangsu person")
      case _        => println("zhejiang person")
    }
  }
}

然后看一下偏函数怎么写:

import scala.util.Random
object MatchApp {
  def main(args: Array[String]): Unit = {
    val regions =Array("anhui","shanghai","jiangsu","zhejiang")
    val region = regions(Random.nextInt(regions.length))
    println(region)
    println(person2(region))

    def person2:PartialFunction[String,String] = {    //一个偏函数,第一个String可以理解是传进来的参数,第二个String可以理解是返回值
      case "anhui" => "anhui person"
      case "shanghai" => "shanghai person"
      case "jiangsu" => "jiangsu person"
      case _        => "zhejiang person"
    }
  }
}

偏函数没有match 。

Tuple

val a = (1,2,3,4,5,6)
括号里面放了一堆东西,你就可以理解为Tuple
然后直接可以这样直接用:
a._1
a._3

举例:

    val a = ("aaa",111,"bbb")
    val b= a._2     //就代表第二个
    val c= a._3     //就代表第三个
    println(b)
    println(c)

输出结果:

111
bbb

Process finished with exit code 0

猜你喜欢

转载自blog.csdn.net/liweihope/article/details/90142360
05
今日推荐