Scala
函数
柯里化(Currying)
-
柯里化指的是将多个参数的函数变成接收单一参数的过程
-
案例
package com.fesco.method object MethodDemo1 { def main(args: Array[String]): Unit = { // 定义一个函数:获取两个数字中较大的那个数字// 基本函数/*def max(a: Int, b: Int): Int = if (a > b) a else bprintln(max(3, 5))*/// 高阶函数def max(a: Int) = {def m(b: Int): Int = if (a > b) a else b m _} val r = max(4)println(r(2))println(r(1))println(max(5)(7)) // max中直接嵌套了一个m函数,所有的计算逻辑都是在m函数中完成,之后直接将m函数返回// 这个过程称之为柯里化def maxCurry(a: Int)(b: Int) = if (a > b) a else b println(maxCurry(4)(3))// 柯里化虽然将闭包的过程进行了简化,但是导致调用的时候必须将参数全部传入val mc = maxCurry(3)(5)println(mc)} }
-
柯里化本质上还是闭包!!!
传名参数
-
案例
package com.fesco.method object MethodDemo2 { def main(args: Array[String]): Unit = { // 定义一个函数,需要接收一个参数,参数的结果导向只要是Int就可以// 接收的是一段逻辑,只要这段逻辑的结果是Int就可以// f的数据类型是 =>Int,也就意味着,是要逻辑的结果是Int类型就可以def twice(f: => Int): Unit = println(f) twice(3)twice(if (3 > 5) 3 else 5) def add(x: Int, y: Int): Int = x + y twice(add(3, 5)) // 要求传入的必须是(Int, Int) => Int的函数def calc(f: (Int, Int) => Int): Unit = println(f)calc(add) } }
-
案例
package com.fesco.method object MethodDemo3 { def main(args: Array[String]): Unit = { // 打印1-10var i = 1while (i <= 10) {println(i)i += 1} println("=" * 50) // 会发现,对于while循环,可以拆分成两部分// 1. 条件 - 在定义while结构的时候,并不知道条件是什么,而是用户在使用的时候来传入。// 对于开发人员而言,只需要确定一件事就可以:条件的结果一定是一个Boolean型// 2. 执行逻辑 - 在定义while结构的时候,需要执行什么逻辑,开发人员不知道//def whileLoop(condition: => Boolean)(body: => Unit): Unit = {// 判断条件是否成立if (condition) {// 只要条件成立,那么就执行逻辑bodywhileLoop(condition)(body)}} var n = 1// 如果({}),那么()可以省略/*whileLoop(n <= 10)({println(n)n += 1})*/whileLoop(n <= 10) {println(n)n += 1}} }
懒加载
-
在函数的返回值之前用
lazy
来修饰,这个函数就会被推迟执行,直到结果被使用的时候,函数才会执行,这个过程就称之为懒加载,或者惰性加载package com.fesco.method object LazyDemo { def main(args: Array[String]): Unit = { def minus(a: Int, b: Int): Int = {println("running")a - b} val m1 = minus(6, 3)println("=" * 50)// minus函数不执行lazy val m2 = minus(7, 2)// 打印m2 ===> m2被使用// 加载执行minus函数println(m2) } }
-
注意:
lazy
只能修饰val不能修饰var
面向对象
类和对象
-
在Scala中,通过
class
来定义类package com.fesco.objectx object PersonDemo { def main(args: Array[String]): Unit = { val p = new Personp.setName("Amy")p setAge 15 println(p.getName)println(p.getAge)println(p.id) } } // 通过class定义类 class Person { // 属性// 在Scala中,不支持先声明后给值// _表示给这个属性默认值var name: String = _var age: Int = _// 常量必须给值,不能使用默认值val id:String = "xxx" // 方法def setName(name: String): Unit = this.name = name def getName = this.name def setAge(age: Int) = this.age = age def getAge = this.age }
-
如果类中没有属性和函数,那么这个类在定义的时候可以省略{}不写
class Driver
-
在Scala中,所有的类默认都是公共的,不需要使用public来修饰。一个scala文件中可以包含多个类
构造器
-
在Scala中,没有构造函数的说法,取而代之的是构造器。Scala中,构造器可以定义多个,分为主构造器和辅构造器
-
主构造器的结构
class 类名(参数列表){ // 主构造器类体 }
-
如果不指定,那么主构造器默认是无参的
// 默认无参 class Person() {} // 含参构造 class Student(var name:String){}
-
如果需要提供新的构造方式,那么需要通过辅构造器来完成
class 类名(参数列表){ // 主构造器def this(参数列表){} // 辅构造器 }
-
辅构造器可以有多个
-
辅构造器中不能定义类的属性!!!
-
辅构造器中第一行必须先调用主构造器
package com.fesco.objectx object StudentDemo { def main(args: Array[String]): Unit = { val s = new Student("David", 15, "fesco")println(s.name)println(s.school)// age不认为是属性,所以s.age是错误的s.info()val s2 = new Student("Bob", 10, 3)println(s2.grade)} } // 主构造器 // var和val定义的参数,默认会编译成这个类的属性 // 没有var和val定义的参数,就是普通变量 class Student(var name: String, age: Int, val school: String) { var grade: Int = _ def this(name: String, age: Int, grade: Int) {// 辅构造器中第一行必须先调用主构造器,或者调用其他的辅构造器this(name, age, "fesco")this.grade = grade} def info(): Unit = println(s"name:${this.name}, age:$age, school:${this.school}") }
权限控制
-
在Scala中一共有三种权限:公共、
protected
和private
-
如果类、属性或者方法之前没有写其他的权限修饰符,那么默认就是公共权限,因此Scala中没有
public
关键字 -
private
和Java一样,修饰的属性和方法只能在本类中使用 -
Scala中的
protected
比Java中更严格,只能在本类中和子类中使用,同包类和其他类中不能使用 -
案例
package com.fesco.objectx object ControlDemo { } // 职业 class Profession { // 没有限定就是公共的val id: Long = 12865496L// 只能在本类和子类中使用protected var department: String = _// 只能在本类中使用private var name: String = _// 限定包的范围 - private[包名]private[objectx] var address: String = _ } class Teacher extends Profession { def info(): Unit = println(s"$id, $department") }
-
案例
package com.fesco.objectx object RectangleDemo { def main(args: Array[String]): Unit = { val r = new Rectangler.height = 5.2println(r.height)r.width = 4.5println(r.width)println(r.area) } } class Rectangle { // 在Scala中,推荐属性使用_开头,和方法做区分private var _height: Double = _private var _width: Double = _ /*def setHeight(height: Double): Unit = this._height = heightdef getHeight: Double = this._height*/def height: Double = _height def height_=(height: Double): Unit = this._height = height def width: Double = _width def width_=(width: Double): Unit = this._width = width def area: Double = this._height * this._width }
包
定义
-
在Scala中,依然是通过
package
来定义包package 包名 // 例如 package com.fesco
-
注意:在Java中,一个
.java
文件中只能有一个package语句;在Scala中,允许定义多个package语句,根据定义顺序,后定义的包是前边包的子包// 方式一: package com.fesco.pa // 方式二 package com package fesco package pa // 方式三 package com.fesco package pa // 方式四 package com package fesco.pa
-
为了表示层级关系,还提供了嵌套风格
package com {package fesco {package pa{}} }
-
注意:在Java中,package语句需要放在
.java
文件的第一行,Scala中不做要求// 如果父包和子包之间没有其他代码,那么不需要写{} package com package fesco // 如果父包和子包之间有其他的代码,那么子包需要写{} package com class Student{} // Student的全路径名是com.Student // fesco是com的子包 package fesco {class Pupil{} // Pupil的全路径名是com.fesco.Pupil } // test是com的子包 package test {class Junior{} // Junior的全路径名是com.test.Junior }
导包
-
在Scala中,依然是通过
import
来导入包,但是Scala中,导包语句可以书写在任何地方object PackageDemo2 {def main(args: Array[String]): Unit = {// 导包语句可以定义在任何位置import java.util.ArrayListval list = new ArrayList[String]()}}
-
导包的时候,用
_
表示通配符// 导入util包下的所有的类但是不包含子包的类 import java.util._ // 导入Collections类中的所有属性和函数 import java.util.Collections._
-
如果导入同一个包下的多个类,可以使用
{}
将类放到同一行上import java.util.{List, ArrayList, Map}
-
Scala中,还允许在导包的时候给类来起别名
import scala.collection.mutable.{Map => MulMap} import scala.collection.immutable.{Map => ImMap} // 导入java.util包下的所有的类,同时将ArrayList的别名定义为AL import java.util.{ArrayList => AL, _} // 可以利用这个方式来屏蔽类 // 表示禁止使用HashMap类 import java.util.{HashMap => _} // 导入java.util包下除了HashMap以外的类 import java.util.{HashMap => _, _}
-
_root_
表示根目录 -
Scala中,默认导入了三个包中的类:
java.lang
包,scala
包,scala.Predef
类
包对象(package object)
-
在Scala中,可以为每一个包来定义一个同名对象,称之为包对象
package object
-
包对象必须和包同名,所以每一个包只能有1个包对象
-
在包对象中,可以定义属性和方法。在同一个包中的所有的类都可以访问同名包对象中的函数和属性
package com.fesco.objectx package testobject PackageDemo {def main(args: Array[String]): Unit = {println(test.add(3, 7))println(test.id)}}package object test {val id = 5846def add(x: Int, y: Int): Int = x + y}
-
在Scala中,可以将这个包中所有的类共享的属性或者函数定义到包对象中
面向对象的特征
-
面向对象的特征:封装、继承、多态。Scala作为一门完全面向对象的语言,一定是符合三大特征
-
封装:Scala中,提供了对象的封装和函数的封装
-
继承:Scala也是通过
extends
关键字来完成继承。同样,Scala支持类和类之间的单继承而不是多继承,子类同样可以通过继承来使用父类中的部分方法或者属性 -
多态:包含了对象的多态(向上造型)和行为的多态(方法的重载和重写)
-
向上造型:父类声明,子类实现
package com.fesco.dtobject ExtendsDemo {def main(args: Array[String]): Unit = {val s: Student = new Pupil}}class Studentclass Pupil extends Student
-
方法的重写:子类继承父类之后,可以覆盖/重写父类中的方法。在Scala中,需要通过
override
关键字来明确定义这个函数是重写的package com.fesco.dtobject ExtendsDemo {def main(args: Array[String]): Unit = {val s: Student = new Pupils.study()}}class Student {def study(): Unit = println("studying") }class Pupil extends Student {// 明确的使用override来定义override def study(): Unit = println("the pupil is studying") }
-
在Scala中,还支持属性的重写。如果父子类中存在同名属性,且该属性用val来定义,那么可以进行属性的重写
package com.fesco.dtobject ExtendsDemo {def main(args: Array[String]): Unit = {val s: Student = new Pupils.study()println(s.versionUID)}}class Student {val versionUID: Long = 54896524Ldef study(): Unit = println("studying") }class Pupil extends Student {// 属性的重写// 只有父类中val定义的属性可以在子类中重写// 父子类中不允许存在同名的var定义的属性!!!override val versionUID: Long = 3248203578L// 明确的使用override来定义override def study(): Unit = println("the pupil is studying") }
-
如果需要判断对象是否是某一个类型,那么可以使用
isInstanceOf
println(s.isInstanceOf[Pupil])
-
类型转换
val p = s.asInstanceOf[Pupil]