scala

Scala

概述

Scala是一门以Java虚拟机(JVM)为运行环境并将面向对象和函数式编程的最佳特性结合在一起的 静态类型编程语言(静态语言需要提前编译的如:Java、c、c++等,动态语言如:js)。

  1. Scala是一门多范式的编程语言,Scala支持面向对象和函数式编程。(多范式,就是多种编程方 法的意思。有面向过程、面向对象、泛型、函数式四种程序设计方法。)
  2. Scala源代码(.scala)会被编译成Java字节码(.class),然后运行于JVM之上,并可以调用现有 的Java类库,实现两种语言的无缝对接。
  3. Scala单作为一门语言来看,非常的简洁高效。

变量和数据结构

注释

Scala 注释使用和 Java 完全一样。

单行注释://

多行注释:/**/

文档注释:/*

​ *

​ */

变量和常量

常量:用val声明 val 常量名 [:常量类型]=初始值

变量:用var声明 var 变量名 [:变量类型]=初始值

注意:

  1. 能用常量的地方不用变量
  2. 声明变量时,类型可以省略,编译器自动推导,即类型推导
  3. 类型确定后,就不能修改,说明 Scala 是强数据类型语言。
  4. 变量声明时,必须要有初始值
  5. 在声明/定义一个变量时,可以使用 var 或者 val 来修饰,var 修饰的变量可改变, val 修饰的变量不可改。
  6. var 修饰的对象引用可以改变,val 修饰的对象则不可改变,但对象的状态(值) 却是可以改变的。

数据类型

  1. Scala中一切数据都是对象,都是Any的子类。
  2. Scala中数据类型分为两大类:数值类型(AnyVal)、 引用类型(AnyRef),不管是值类型还是引用类型都是 对象。
  3. Scala数据类型仍然遵守,低精度的值类型向高精 度值类型,自动转换(隐式转换)
  4. Scala中的StringOps是对Java中的String增强
  5. Unit:对应Java中的void,用于方法返回值的位置,表 示方法没有返回值。Unit是 一个数据类型,只有一个对象 就是()。Void不是数据类型,只是一个关键字
  6. Null是一个类型,只 有一个对 象就 是null。它是 所有引用类型(AnyRef)的子类。
  7. Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使 用

在这里插入图片描述

整数类型

在这里插入图片描述

浮点类型

在这里插入图片描述

字符类型

字符类型可以表示单个字符,字符类型是 Char。

布尔类型

布尔类型也叫 Boolean 类型,Booolean 类型数据只允许取值 true 和 false。Boolean 类型占 1 个字节。

Unit 类型、Null 类型和 Nothing 类型

在这里插入图片描述

  1. Unit 类型用来标识过程,也就是没有明确返回值的函数。
  2. Null 类只有一个实例对象,Null 类似于 Java 中的 null 引用。Null 可以赋值给任 意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)
  3. Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方 法不会正常返回,而且由于 Nothing 是其他任意类型的子类,他还能跟要求返回值的方法兼 容。
类型转换

自动转换(隐士转换):精度小的自动向精度大的转换

强制类型转换:调用toXxx()方法

运算符

算术运算符

在这里插入图片描述

对于除号“/”,它的整数除和小数除是有区别的:整数之间做除法时,只保留整 数部分而舍弃小数部分。

对一个数取模 a%b,和 Java 的取模规则一样。

关系运算符

在这里插入图片描述

==与equals

java: ==比较两个变量本身的值,即两个对象在内存中的首地址;equals 比较字符串中所包含的内容是否相同。

scala:==更加类似于 Java 中的 equals

逻辑运算符

在这里插入图片描述

赋值运算符

在这里插入图片描述

位运算符

在这里插入图片描述

流程控制

分支控制

if(条件表达式){
    执行代码块
}[else if(条件表达式){
    执行代码块
}][else{
    执行代码块
}]
object s03 {
  def main(args: Array[String]): Unit = {
    println("input age")
    var age=StdIn.readInt()
    if(age<18){
      println("童年")
    }else if(age>=18&&age<30){
      println("中年")
    }else{
      println("老年")
    }
  }
}

Scala 中 if else 表达式其实是有返回值的,具体返回值取决于满足条件的 代码体的最后一行内容。

val res:String=if(age<18){
              "童年"
            }else if(age>=18&&age<30){
              "中年"
            }else{
              "老年"
            }
    println(res)

Scala 中返回值类型不一致,取它们共同的祖先类型。

val res:Any=if(age<18){
              "童年"
            }else if(age>=18&&age<30){
              "中年"
            }else{
              100
            }
    println(res)

for循环

Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称 为 for 推导式或 for 表达式。

for(变量<-a to b by c){//[a,b] 步长为 c
    todo
}
for(变量 <-a until b by c){//[a,b) 步长c
    todo
}
循环守护

循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环 体内部,为 false 则跳过,类似于 continue。

for(变量 <-a to b if 关于变量的条件语句){
    todo
}
循环返回值
val res = for(i <- 1 to 10) yield i
println(res)

将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。

while与do…while

与java相同

函数式编程

Scala 语言是一个完全面向对象编程语言。万物皆对象

对象的本质:对数据和行为的一个封装

Scala 语言是一个完全函数式编程语言。万物皆函数。

函数的本质:函数可以当做一个值进行传递

在这里插入图片描述

函数和方法的区别

方法有访问权限,函数没有访问权限

为完成某一功能的程序语句的集合,称为函数。

类中的函数称之方法。

函数没有重载和重写的概念;方法可以进行重载和重写

Scala 中函数可以嵌套定义

函数至简原则

函数至简原则:能省则省

  1. return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
  2. 如果函数体只有一行代码,可以省略花括号
  3. 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)。如果有 return,则不能省略返回值类型,必须指定
  4. 如果函数明确声明 unit,那么即使函数体中使用 return 关键字也不起作用
  5. Scala 如果期望是无返回值类型,可以省略等号
  6. 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加
  7. 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
  8. 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

高级函数

  1. 函数可以作为值进行传递
  2. 函数可以作为参数进行传递
  3. 函数可以作为函数返回值返回
匿名函数

没有名字的函数就是匿名函数。

(x:Int)=>{函数体}

x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

传递匿名函数至简原则:

  1. 参数的类型可以省略,会根据形参进行自动的推导
  2. 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参 数超过 1 的永远不能省略圆括号。
  3. 匿名函数如果只有一行,则大括号也可以省略
  4. 如果参数只出现一次,则参数省略且后面参数可以用_代替
闭包

如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的 环境,称为闭包。

object TestFunction {
 def main(args: Array[String]): Unit = {
 def f1()={
var a:Int = 10
 def f2(b:Int)={
 a + b
 }
 f2 _
 }
 // 在调用时,f1 函数执行完毕后,局部变量 a 应该随着栈空间释放掉
 val f = f1()
 // 但是在此处,变量 a 其实并没有释放,而是包含在了 f2 函数的内部,形成了闭合的效果
 println(f(3))
 
 println(f1()(3))
// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存
在闭包
 def f3()(b:Int)={
 a + b
 }
 println(f3()(3))
 }
}
函数柯里化

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。

惰性加载

当函数被调用是先执行被调函数里的语句。

当函数返回值被声明为 lazy 时,函数的执行将被推迟,直到我们首次对此取值,该函 数才会执行。这种函数我们称之为惰性函数。

def main(args: Array[String]): Unit = {
 lazy val res = sum(10, 30)
 println("----------------")
 println("res=" + res)//只有res调用sum函数才执行
}
def sum(n1: Int, n2: Int): Int = {
 println("sum 被执行。。。")//只有res调用该语句才输出
 return n1 + n2
}

azy 不能修饰 var 类型的变量

面向对象

[修饰符]class 类名{
    类体
}

Scala 语法中,类并不声明为 public,所有这些类都具有公有可见性(即默认就是 public)

一个scala源文件可以包含多个类

创建对象

val | var 对象名[:类型]=new 类型()

val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

var 修饰对象,可以修改对象的引用和修改对象的属性值

自动推导变量类型不能多态,所以多态需要显示声明

构造器

Scala 类的构造器包括:主构造器和辅助构造器

class 类名(形参列表){//主构造器
    def this(形参列表){//辅助构造器
        
    }
}

辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型 来区分。

辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

构造器调用其他另外的构造器,要求被调用构造器必须提前声明。

构造器参数

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

  1. 未用任何修饰符修饰,这个参数就是一个局部变量 。
  2. var 修饰参数,作为类的成员属性使用,可以修改 。
  3. val 修饰参数,作为类只读属性使用,不能修改

继承

class Person(nameParam: String) {
 var name = nameParam
 var age: Int = _
 def this(nameParam: String, ageParam: Int) {
 this(nameParam)
 this.age = ageParam
 println("父类辅助构造器")
 }
 println("父类主构造器")
}
class Emp(nameParam: String, ageParam: Int) extends 
Person(nameParam, ageParam) {
 var empNo: Int = _
 def this(nameParam: String, ageParam: Int, empNoParam: Int) {
 this(nameParam, ageParam)
 this.empNo = empNoParam
 println("子类的辅助构造器")
 }
 println("子类主构造器")
}
object Test {
 def main(args: Array[String]): Unit = {
 new Emp("z3", 11,1001)
 }
}

特质

Scala 语言中,采用特质 trait(特征)来代替接口的概念,也就是说,多个类具有相同 的特质(特征)时,就可以将这个特质(特征)独立出来,采用关键字 trait 声明。

Scala 中的 trait 中即可以有抽象属性和方法,也可以有具体的属性和方法,一个类可 以混入(mixin)多个特质。这种感觉类似于 Java 中的抽象类。

Scala 引入 trait 特征,第一可以替代 Java 的接口,第二个也是对单继承机制的一种 补充。

一个类具有某种特质(特征),就意味着这个类满足了这个特质(特征)的所有要素, 所以在使用时,也采用了 extends 关键字,如果有多个特质或存在父类,那么需要采用 with 关键字连接。

没有父类:class 类名 extends 特质 1 with 特质 2 with 特质 3 …

有父类:class 类名 extends 父类 with 特质 1 with 特质 2 with 特质 3…

说明 :

  1. 类和特质的关系:使用继承的关系。
  2. 当一个类去继承特质时,第一个连接词是 extends,后面是 with。
  3. 如果一个类在同时继承特质和父类时,应当把父类写在 extends 后。
特质叠加

由于一个类可以混入(mixin)多个 trait,且 trait 中可以有具体的属性和方法,若混入 的特质中具有相同的方法(方法名,参数列表,返回值均相同),必然会出现继承冲突问题。 冲突分为以下两种:

第一种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 之间没有任何关系,解决这类冲突问题,直接在类(Sub)中重写冲突方法。

第二种,一个类(Sub)混入的两个 trait(TraitA,TraitB)中具有相同的具体方法,且 两个 trait 继承自相同的 trait(TraitC),及所谓的“钻石问题”,解决这类冲突问题,Scala 采用了特质叠加的策略。

所谓的特质叠加,就是将混入的多个 trait 中的冲突方法叠加起来

trait Ball {
 def describe(): String = {
 "ball"
 }
}
trait Color extends Ball {
 override def describe(): String = {
 "blue-" + super.describe()
 }
}
trait Category extends Ball {
 override def describe(): String = {
 "foot-" + super.describe()
 }
}
class MyBall extends Category with Color {
 override def describe(): String = {
 "my ball is a " + super.describe()
 }
}
object TestTrait {
 def main(args: Array[String]): Unit = {
 println(new MyBall().describe())
 }
}
//结果:my ball is a blue-foot-ball
特质叠加执行顺序

上述案例中的 super.describe()调用的是父 trait 中的方法吗?

案例中的 super,不是表示其父特质对象,而是表示上述叠加顺序中的下一个特质, 即,MyClass 中的 super 指代 Color,Color 中的 super 指代 Category,Category 中的 super 指代 Ball。

如果想要调用某个指定的混入特质中的方法,可以增加约束:super[],例如 super[Category].describe()。

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alonzo de blog

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值