首页 > 其他分享 >Scala--纯粹的面向对象语言

Scala--纯粹的面向对象语言

时间:2024-02-05 11:36:49浏览次数:35  
标签:name val Scala -- 面向对象 println def String

Scala是一种多范式的编程语言,它将面向对象和函数式编程结合在一个简洁的高级语言中,Scala运行于Java平台(Java虚拟机),并兼容现有的Java程序。

Scala基于JVM, 和Java完全兼容, 同样具有跨平台,可以执行好,方便的垃圾回收等特性;
Scala是一种纯粹的面向对象语言;
Scala是一门函数式编程语言;
Scala更适合大数据的处理

Scala对集合类型数据处理有非常好的支持
Spark的底层用Scla编写, 深入学习Spark必定要掌握Scala

Scala 与 Java, JVM的关系

 

1.3 Scala语言的特点

 

2.为什么要学Scala
优雅:这是框架设计师第一个要考虑的问题,框架的用户是应用开发程序员,API是否优雅直接影响用户体验。
速度快:Scala语言表达能力强,一行代码抵得上Java多行,开发速度快;Scala是静态编译的,所以和JRuby,Groovy比起来速度会快很多。
能融合到Hadoop生态圈:Hadoop现在是大数据事实标准,Spark并不是要取代Hadoop,而是要完善Hadoop生态。JVM语言大部分可能会想到Java,但Java做出来的API太丑,或者想实现一个优雅的API太费劲。
3.Scala基础语法
1.声明变量
package com.lyz.scala.day1
Object HelloScala{
def main(args: Array[String]):Unit={

//使用val定义的变量值是不可变的,相当于java里用final修饰的变量
val i = 1
//使用var定义的变量是可变得,在Scala中鼓励使用val
var s = "hello"
//Scala编译器会自动推断变量的类型,必要的时候可以指定类型
//变量名在前,类型在后
val str: String = "itcast"
}
}
​​​​​​ 2.常用类型
Scala和Java一样,有7种数值类型Byte、Short、Int、Long、Char、Float和Double(无包装类型)和一个Boolean类型 

Scala环境安装配置

注意:由于Scala是基于Java虚拟机的,所以使用 Scala 之前必须先安装 Java,Java我们已经安装过了。
那在这里我们先到官网下载Scala安装包

下载地址,这里我们使用2.12.11版本

Scala命令行

scala

Scala命令行也称为Scala解释器(REPL),它会快速编译Scala代码为字节码,然后交给JVM来执行

这里的REPL表示:Read(取值)-> Evaluation(求值)-> Print(打印)-> Loop(循环)
在Scala命令行内,输入Scala代码,解释器会直接返回结果

如果你没有指定变量来存放计算的值,那么值默认的名称会显示为res开头的变量,而且会显示结果的数据类型

如果想在scala REPL中执行多行代码,该如何操作?
使用 :paste 和 ctrl+D 的方式
:paste 表示代码块的开始
ctrl+D 表示代码块的结束

IDEA开发配置   (https://www.cnblogs.com/strongmore/p/17355089.html)

安装Scala插件,添加Scala的SDK

Scala的基本使用

scala很多语法和kotlin都很类似,如定义变量,不需要分号,函数等。

变量

Scala中的变量分为两种:可变 var 和 不可变 val
可变var:可以随时修改var声明的变量的值
不可变val:val声明的变量,值不能被修改,否则会报错: error: reassignment to val

注意:在实际工作中,针对一些不需要改变值的变量,通常建议使用val,这样可以不用担心值被错误的修改(等于java中的final类型)。这样可以提高系统的稳定性和健壮性!

无论声明val变量,还是声明var变量,都可以手动指定变量的类型,如果不指定,Scala会自动根据值,进行类型推断
val c = 1 等价于 val c: Int = 1

数据类型

Scala中的数据类型可以分为两种,基本数据类型和增强版数据类型

  • 基本数据类型有: Byte、Char、Short、Int、Long、Float、Double、Boolean
  • 增强版数据类型有: StringOps、RichInt、RichDouble、RichChar 等

scala使用这些增强版数据类给基本数据类型增加了上百种增强的功能

例如:RichInt提供的有一个to函数, 1.to(10) ,此处Int会先隐式转换为RichInt,然后再调用其to函数

val inclusive = 1 to 10
for (i <- inclusive) {
  print(i + " ")
}
println()
val inclusive2 = 1.to(10)
for (i <- inclusive2) {
  print(i + " ")
}

操作符

Scala的算术操作符与Java的算术操作符没有什么区别
比如 +、-、*、/、% 等,以及 &、|、^、>>、<< 等

注意:Scala中没有提供++、–-操作符
我们只能使用+和-,比如count = 1,count++是错误的,必须写做count += 1

if 表达式

在Scala中,if表达式是有返回值的,就是if或者else中最后一行语句返回的值,这一点和java中的if是不一
样的,java中的if表达式是没有返回值的
例如: val age = 20; if (age > 18) 1 else 0

val score = 90
val level = if (score > 90) "A" else "B"
println(level)

由于if表达式是有值的,而if和else子句的值的类型可能还不一样,此时if表达式的值是什么类型呢?

注意:Scala会自动进行推断,取两个类型的公共父类型

如果if后面没有跟else,则默认else的值是Unit,也可以用()表示,类似于java中的void或者null

语句终结符

Scala默认不需要语句终结符,它将每一行作为一个语句
如果一行要放多条语句,则前面的语句必须使用语句终结符,语句终结符和Java中的一样,就是我们平时使用的分号

循环

for (i <- 5 until 10) {
  print(i + " ")
}
//迭代字符串
for (i <- "hello") {
  print(i + " ")
}
println()
var n = 10
while (n > 0) {
  print(n + " ")
  n -= 1
}

1 to 10 可以获取1~10之间的所有数字
1 until 10可以获取1~9之间的所有数字

高级for循环

//if守卫
for (i <- 1 to 10 if i % 2 == 0) {
  print(i + " ")
}
//for推导式
val ages = for (i <- 1 to 5) yield i * i
println(ages.toList)

Scala的集合体系

image

Scala中的集合是分成可变和不可变两类集合的

  • 其中可变集合就是说,集合的元素可以动态修改,在 scala.collection.mutable 这个包下面
  • 而不可变集合就是说,集合的元素在初始化之后,就无法修改了,在 scala.collection.immutable 这个包下面
//不可变集合
val set = Set(1, 1, 2, 3)
println(set)
//可变集合
val set2 = scala.collection.mutable.Set(1, 2, 3)
set2.add(4)
println(set2)
//不可变列表
val list = List(1, 2, 3)
println(list)
//可变列表
val listBuffer = scala.collection.mutable.ListBuffer(1, 2, 3)
listBuffer.append(4)
println(listBuffer.toList)
//不可变Map
val map = Map("name" -> "lisi", "age" -> 20)
println(map)
val map2 = scala.collection.mutable.Map("name" -> "lisi", "age" -> 20)
map2.put("address", "上海")
println(map2)
println(map2.get("name1")) # 如果存在,返回的是Option对象,类似java中的Optional,get()方法获取数据
//println(map2("name1")) 不存在抛异常
println(map2.getOrElse("name1", "lisi2"))
//不可变数组 求和 排序
val array = Array(2, 1, 3)
println(array.sum)
println(array.max)
println(array(0))
Sorting.quickSort(array)
println(array.toList)
//可变数组
val arrayBuffer = scala.collection.mutable.ArrayBuffer(2, 1, 3)
arrayBuffer.append(4)
println(arrayBuffer.toList)
//元组 数据不可变
val tuple = Tuple3(1, 2, "12")
println(tuple)

Scala中函数的使用

在Scala中定义函数需要使用 def 关键字,函数包括函数名、参数、函数体

Scala要求必须给出函数所有参数的类型,但是函数返回值的类型不是必须的,因为Scala可以自己根据函数体中的表达式推断出返回值类型。
函数中最后一行代码的返回值就是整个函数的返回值,不需要使用return,这一点与Java不同,java中函数的返回值是必须要使用return的

//单行函数
  def sum(a: Int, b: Int): Int = a + b

  //多行函数 包含默认参数
  def sum2(a: Int, b: Int = 0): Int = {
    //默认最后一行代码的返回值就是函数的返回值
    a + b
  }

  //可变参数
  def sum3(nums: Int*): Int = {
    var sum = 0
    for (num <- nums) {
      sum += num
    }
    sum
  }

  //特殊的函数-过程 没有使用= 返回值就是Unit
  def sum4(a: Int, b: Int) {
    println(a + b)
  }

  //特殊的函数-过程
  def sum5(a: Int, b: Int): Unit = {
    println(a + b)
  }
  
println(sum(1, 4))
//使用参数名来传参
println(sum2(b = 6, a = 5))
println(sum3(1, 2, 3, 4))

过程是不需要返回值的函数

def sayHello(name: String) = "Hello, " + name
def sayHello(name: String): String = "Hello, " + name
def sayHello(name: String) { "Hello, " + name }
def sayHello(name: String): Unit = "Hello, " + name

前面两种写法的效果是一样的,都是函数
后面两种写法的效果是一样的,都是过程

//延迟读取文件
lazy val fileSource = Source.fromFile("C:/D-myfiles/testjar/test.txt")
val lines = fileSource.mkString
fileSource.close()
println(lines)

如果将一个变量声明为lazy,则只有在第一次使用该变量时,变量对应的表达式才会发生计算

即使文件不存在,代码也不会报错,只有变量使用时才会报错,这就是lazy这个特性。

Scala面向对象编程

Scala中类和java中的类基本是类似的
Scala中的对象时需要定义的,而java中的对象是通过class new出来的
Scala中的接口是trait,java中的接口是interface

类-class

object Demo2 {
  def main(args: Array[String]): Unit = {
    val person = new Person
    person.printName()
    person.printName
  }
  class Person {
    var name = "lisi"
    def printName(): Unit = {
      println(name)
    }
  }
}

如果在定义方法的时候指定了(),那么在调用的时候()可写可不写,如果在定义方法的时候
没指定(),则调用方法时肯定不能带()

Scala类中的构造函数可以分为主构造函数和辅助构造函数
这两种构造函数有什么区别呢?
主constructor:类似Java的默认构造函数 this()
辅助constructor:类似Java的重载构造函数 this(name,age)

object Demo2 {
  def main(args: Array[String]): Unit = {
    val student = new Student("lisi")
    println(student)
    val student2 = new Student("lisi", 23)
    println(student2)
  }

  class Student(name: String) {
    var age = 0

    def this(name: String, age: Int) {
      this(name)
      this.age = age
    }

    override def toString: String = {
      "%s,%s".format(name, age)
    }
  }
}

Scala中,可以给类定义多个辅助constructor,类似于java中的构造函数重载
辅助constructor之间可以互相调用,但是第一行必须调用主constructor

对象-object

object:相当于class的单个实例,通常在里面放一些静态的field或者method

object不能定义带参数的constructor,只有空参的constructor
第一次调用object的方法时,会执行object的constructor,也就是执行object内部不在任何方法中的代码,因为它只有空参的构造函数

但是注意,object的constructor的代码只会在他第一次被调用时执行一次,以后再次调用就不会再执行了

object通常用于作为单例模式的实现,或者放class的一些静态成员,比如工具方法

object可以直接使用,不能new

object Demo2 {
  def main(args: Array[String]): Unit = {
    Teacher.teach()
  }
  object Teacher {
    var name = "Tom"

    def teach(): Unit = {
      println(name + " teach")
    }
  }
}

伴生对象

如果有一个class,还有一个与class同名的object,那么就称这个object是class的 伴生对象 ,class是 object的 伴生类

import scala.collection.mutable.ListBuffer

object Demo2 {
  def main(args: Array[String]): Unit = {
    val list = new IntList(1, 2, 3)
    println(list)
    val list2 = IntList(1, 2, 3)
    println(list2)
  }

  class IntList() {
    var delegate: ListBuffer[Int] = ListBuffer()

    def this(nums: Int*) {
      this()
      for (elem <- nums) {
        this.delegate.append(elem)
      }
    }

    override def toString: String = delegate.toString
  }

  object IntList {
    def apply(nums: Int*): IntList = {
      //new IntList(nums) 这种方式不行 原因未知
      val list = new IntList()
      for (elem <- nums) {
        list.delegate.append(elem)
      }
      list
    }
  }

}

apply是object中非常重要的一个特殊方法,通常在伴生对象中实现apply方法,并在其中实现构造伴生类对象的功能
在创建对象的时候,就不需要使用new Class的方式,而是使用Class()的方式,隐式调用伴生对象的apply方法,这样会让对象创建更加简洁

例如:Array的伴生对象的apply方法就实现了接收可变数量的参数,以及会创建一个Array对象
val a = Array(1, 2, 3, 4, 5)

接口-trait

Scala中的接口称为trait,trait类似于Java中的interface
在triat中可以定义抽象方法

类可以使用 extends 关键字继承trait,无论继承类还是trait统一都是使用 extends 这个关键字

类继承trait后,必须实现trait中的抽象方法,实现时不需要使用 override 关键字

scala不支持对类进行多继承,但是支持对trait进行多重继承,使用 with 关键字即可

class MyRunner extends Runnable with MyRunnable {
    override def run(): Unit = {
      println("run ...")
    }
    override def run2(): Unit = {
      println("run2 ...")
    }
  }
  trait Runnable {
    def run(): Unit
  }
  trait MyRunnable {
    def run2(): Unit
  }

main方法

Scala中的main方法必须定义在object中,格式为 def main(args: Array[String])

函数式编程

在Scala中,函数与类、对象一样,都是一等公民,所以说scala的面向过程其实就重在针对函数的编程了,所以称之为函数式编程

object Demo3 {
  def main(args: Array[String]): Unit = {
    //函数赋值给变量
    var mySum = sum _
    println(mySum(2, 4))
    //匿名函数
    var mySum2 = (a: Int, b: Int) => a + b
    println(mySum2(3, 6))
    //函数当做参数
    println(sum2(a => a * a, 1, 2, 3))
    //内置高阶函数 类似java中的StreamAPI
    val listSum = List(1, 2, 3)
      .filter(a => a % 2 != 0) //可以简写为 _ % 2 != 0   _就表示遍历中的元素
      .map(a => a * a)
      .sum
    println(listSum)
    val listJoin = List("hello you", "hello me")
      .flatMap(a => a.split(" ").toList)
      .reduceLeft((a: String, b: String) => a + "-" + b)
    println(listJoin)
  }
  def sum(a: Int, b: Int): Int = {
    a + b
  }
  def sum2(func: Int => Int, nums: Int*): Int = {
    var sum = 0
    for (elem <- nums) {
      sum += func(elem)
    }
    sum
  }
}

模式匹配

模式匹配是Scala中非常有特色,非常强大的一种功能。
模式匹配,其实类似于Java中的 switch case 语法,即对一个值进行条件判断,然后针对不同的条件,进行不同的处理

object Demo4 {
  def main(args: Array[String]): Unit = {
    //值匹配
    println(week(1))
    println(week(2))
    println(week(3))
    //类型匹配
    processException(new IllegalArgumentException("error"))
    processException(new IOException("error"))
    processException(new Exception("error"))
    //case class 匹配
    println(checkPerson(Teacher("Tom")))
    println(checkPerson(Student("Jack")))
    println(checkPerson(new Person()))
  }

  def checkPerson(p: Person): String = {
    p match {
      case Teacher(name) => "Teacher"
      case Student(name) => "Student"
      case _ => "None"
    }
  }

  class Person

  case class Teacher(name: String) extends Person

  case class Student(name: String) extends Person

  def processException(e: Exception): Unit = {
    e match {
      case e1: IllegalArgumentException => println("IllegalArgumentException: " + e)
      case e2: IOException => println("IOException: " + e)
      case e3: Exception => println("Exception: " + e)
    }
  }
  def week(day: Int): String = {
    day match {
      case 1 => "Monday"
      case 2 => "Tuesday"
      case _ => "None"
    }
  }
}

当一个类被声明为case class的时候,scala会帮助我们做下面几件事情:

  1. 构造器中的参数如果不被声明为var的话,它默认的话是val类型的,但一般不推荐将构造器中的参数声明为var;
  2. 自动创建伴生对象,同时在里面给我们实现apply方法,使得我们在使用的时候可以不直接显示地new对象;
  3. 伴生对象中同样会帮我们实现unapply方法,从而可以将case class应用于模式匹配;
  4. 实现自己的toString、hashCode、copy、equals方法。

除此之此,case class与其它普通的scala类没有区别。

隐式转换

Scala的隐式转换,允许手动指定将某种类型的对象转换成其它类型的对象

Scala的隐式转换,最核心的就是定义隐式转换函数,即implicit conversion function

隐式转换函数与普通函数唯一的语法区别是要以implicit开头而且最好要定义函数返回类型

隐式转换非常强大的一个功能,就是可以在不知不觉中加强现有类型的功能。也就是说,我们可以为某个普通类定义一个加强类,并定义对应的隐式转换函数,这样我们在使用加强类里面的方法的时候,Scala会自动进行隐式转换,把普通类转换为加强类,然后再调用加强类中的方法

object Demo5 {
  def main(args: Array[String]): Unit = {
    val dog = new Dog("Tom")
    dog.catchMouse()
  }

  class Cat(name: String) {
    def catchMouse() {
      println(this.name + " catch mouse")
    }
  }

  class Dog(val name: String)

  implicit def object2Cat(obj: Object): Cat = {
    if (obj.getClass == classOf[Dog]) {
      val dog = obj.asInstanceOf[Dog]
      new Cat(dog.name)
    }
    else Nil
  }
}

我们后续在工作中一般很少需要我

 


参考:https://blog.csdn.net/weixin_38201936/article/details/89608537

https://blog.csdn.net/weixin_51996831/article/details/123329304

 

标签:name,val,Scala,--,面向对象,println,def,String
From: https://www.cnblogs.com/klb561/p/18007641

相关文章

  • Erlang 学习之第三天 . 函数,模块,递归,数字,字符串
    Erlang函数Erlang是一种众所周知的函数式编程语言,因此您将看到许多关于函数如何在Erlang中工作的重点。本章介绍如何使用Erlang中的函数完成所有操作。直接上实例:定义函数add(X,Y) ->    Z = X+Y,    io:fwrite("~w~n",[Z]). start() ->    add(5,6).......
  • 冒泡排序 Bubble Sort
    一种将无序数组,按递增/减顺序排序的方法从第一个元素和第二个元素开始,依次两两比较,当第n个元素小于第n+1个元素时,两元素交换位置。再从第二个和第三个元素开始重复上述动作直至遍历整个数组时间复杂度:最坏情况:O(N^2)      最好情况:O(N^2)空间复杂度:O(1)/**......
  • 关于头文件的使用
    关于头文件的使用这里写一下这个东西,毕竟我在使用的时候还是有不少的疑问一、头文件头文件就是在写C++代码的时候,在最开头几行引用的文件,这里比如说:#include<iostream>我们就是引用了一个名称为iostream的头文件这里这个文件为什么没有后缀名呢,这我就不是很清楚了,据......
  • 使用C语言构建一个独立栈协程和共享栈协程的任务调度系统
    使用了标准库头文件<setjmp.h>中的setjmp和longjmp两个函数,构建了一个简单的查询式协作多任务系统,支持独立栈和共享栈两种任务。其中涉及到获取和设置栈的地址操作,因此还需要根据不同平台提供获取和设置栈的地址操作(一般是汇编语言,因为涉及到寄存器)该调度系统仅运行在一个......
  • 《程序是怎样跑起来的》第一章总结
    第一章的主要内容就是对CPU进行了详细的解释.CPU相当于计算机的大脑,它有数百万至数一个晶体管构成.CPU的内部主要有控制器,运算器,寄存器和时钟构成.如寄存器可用来暂存指令,数据等处理对象可以将其看作是内存的一种,控制器负责把内存上的指令,数据等读人寄存器,并......
  • 技术人员核心能力 -- 危机处理能力
    工作生活中难免会遇到一些非常重大的危机、出现重大致命的BUG、如何面对?如何处理?如何化解危机?如何复盘?如何防止相同的事情重复发生?建立什么样的机制?定什么规章制度?     如何应对危机?如何高效率沟通协调?危机应对的多了处理经验也更丰富了、也不会怕遇到任何危机了、......
  • SM学习总结
    图的应用(1)---updatebylgj   拓扑序列 测试1  拓扑序列练习  测试2 拓扑排序-cn是大帅哥886-博客园(cnblogs.com) 断网测试1 断网测试1-拓扑排序-TimelineG(拓扑排序)-cn是大帅哥886-博客园(cnblogs.com) priority_queue简介与用法......
  • 计算机体系结构
    计算机体系结构是指计算机系统的设计和组织方式,它包括计算机硬件、软件、数据存储和通信等方面。计算机体系结构的发展经历了多个阶段,从简单的单处理器系统到复杂的多核系统和分布式系统。在现代计算机体系结构中,处理器是计算机系统的核心组件,它负责执行指令和处理数据。处理器的......
  • PMP-7.1 结束项目或阶段文档--最终报告--组织收获(组织过程资产更新)
    一、最终报告用最终报告总结项目绩效,其中可包含诸如以下信息:1.项目或阶段的概述2.范围目标、范围的评估标准,以及证明达到完工标准的证据3.质量目标、项目和产品质量的评估标准、相关核实信息和实际里程碑交付日期以及偏差原因4.成本目标,包括可接受的成本区间、实际成本,以......
  • 寒假day4 2.5
    讲师:钟皓曦,NOI2012Au,from成都七中dp树形dp核心:在树上做的dp给定一棵\(n\)个点的树,求这棵树有几个点。对于树形dp,第一个维度是\(f_i\),代表以\(i\)为根的子树内的信息(有几个点)树形dp的转移方法是把所有儿子信息整合所有儿子的dp值\(\rightarrow\)自己。转移:\(......