一、 类、对象、继承、特质
1.类
Scala的类与Java、C++的类比起来更简洁
定义:
package com.jiangbei
//在Scala中,类并不用声明为public。
//Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
class Person {
// 定义一个不可变的val(只有getter)和可变的var(getter setter都有)
// 更直观的理解,可以通过反编译工具打开out目录的.class文件
val id = 9527
var name = "唐伯虎"
}
当然,变量和Java一样可以进行访问控制:
//类私有字段,只能在类的内部使用
private var name: String = "唐伯虎"
//对象私有字段,访问权限更加严格的,Person类的方法只能访问到当前对象的字段
private[this] val pet = "小强"
构造器:
package com.jiangbei
/**
*每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起
* 注意:主构造器会执行类定义中的所有语句
* 如果主构造器中的参数没有加val var等,则为private,无法外部访问
* 构造器参数可以不带val或var,如果不带val或var的参数至少被一个方法所使用,那么它将会被提升为字段
* //在类名后面加private就变成了私有的
class Queen private(val name: String, prop: Array[String], private var age: Int = 18){
*
*/
class Person(var age: Int, name: String) {
private var gender = "love"
//用this关键字定义辅助构造器
def this(name: String, age: Int, gender: String){
//每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
this(age, name)
println("执行辅助构造器")
this.gender = gender
}
}
object Person{
def main(args: Array[String]): Unit = {
val p1 = new Person(18, "SMD")
println(p1.age)
// println(p1.name)
}
}
2.对象
单例对象
在Scala中没有静态方法和静态字段,但是可以使用object这个语法结构来达到同样的目的
1.存放工具方法和常量
2.高效共享单个不可变的实例
3.单例模式
package com.jiangbei
object Singleton {
// object中定义的方法变量的都是静态的(静态方法、静态块)
def main(args: Array[String]): Unit = {
val s = Singleton
println(s) // com.jiangbei.Singleton$@5e025e70
}
}
伴生对象
在Scala的类中,与类名相同的对象叫做伴生对象,类和伴生对象之间可以相互访问私有的方法和属性
一般伴生对象和类写在一个文件
class Person(var age: Int, name: String) {
private var gender = "love"
}
object Person{
def main(args: Array[String]): Unit = {
val p1 = new Person(18, "SMD")
println(p1.gender)
}
}
apply方法
通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用
class Person() {
}
object Person{
def apply():Unit = {
println("apply被调用!")
}
def apply(name: String):Unit = {
println(name)
}
def main(args: Array[String]): Unit = {
// 以下的Person()会自动调用对应的无参的apply()方法,这里的p1就是返回值了。
// 如果有多个,则对应参数相应的
val p1 = Person()
val p2 = Person("小强")
}
}
结果:
apply被调用!
小强
应用程序对象
Scala程序都必须从一个对象的main方法开始,可以通过扩展App特质,不写main方法。(意义不大,不常用)
object AppObjectDemo extends App{
//不用写main方法
println("I love you Scala")
}
3.继承
继承:与Java保持一致,使用extands,实现接口使用with(with Flyable with Human)
重写:使用override修饰符
类型转换和类型检查:
Scala |
Java |
obj.isInstanceOf[C] |
obj instanceof C |
obj.asInstanceOf[C] |
(C)obj |
classOf[C] |
C.class |
实例:
package com.jiangbei
object Singleton {
// object中定义的方法变量的都是静态的(静态方法、静态块)
def main(args: Array[String]): Unit = {
val b1 = new Bird
b1.run()
b1.flight()
}
}
// 相当于Java8的接口,可以有默认实现
trait Flyable {
def fly(name: String): Unit = {
println(name + " can fly!")
}
// 未实现方法
def flight(): Unit
}
abstract class Animal {
val name: String
def run(): Unit
}
class Bird extends Animal with Flyable {
override val name: String = "love"
override def run(): Unit = {
println("bird run!")
}
override def flight(): Unit = {
println("bird flight")
}
}
// 详细待更新
二、模式匹配和样例类
Scala有一个十分强大的模式匹配机制,可以应用到很多场合:如switch语句、类型检查等。
并且Scala还提供了样例类,对模式匹配进行了优化,可以快速进行匹配
一个模式匹配包含了一系列备选项,每个都开始于关键字 case。每个备选项都包含了一个模式及一到多个表达式。箭头符号 =>隔开了模式和表达式。
1.字符串匹配
def main(args: Array[String]): Unit = {
val colors = Array("red", "green", "blue")
val color = colors(Random.nextInt(colors.length))
println("给你点颜色看看..")
color match {
case "blue" => println("蓝色")
case "green" => println("绿色")
case "red" => println("红色")
case _ => println("不知道你在说什么..")
}
}
2.类型匹配
def main(args: Array[String]): Unit = {
val colors = Array("red", 1, 3.0)
val color = colors(Random.nextInt(colors.length))
println("给你点颜色看看..")
color match {
case x: String => println(x)
case y: Int if y > 0 => println("大于0的整型")
case Double => println("双精度浮点型")
case _ => throw new Exception("类型不匹配!")
}
}
3.数组、元组匹配
def main(args: Array[String]): Unit = {
val arr = Array(1, 2 ,3)
arr match {
case Array(1, x, y) => println(x)
case Array(0) => println("0")
// 1开头的,后面任意
case Array(1, _*) => println("0...")
case _ => throw new Exception("类型不匹配!")
}
val lst = List(3, -1)
lst match {
case 0 :: Nil => println("only 0")
case x :: y :: Nil => println(s"x: $x y: $y")
case 0 :: tail => println("0 ...")
case _ => println("something else")
}
val tup = (2, 3, 7)
tup match {
case (1, x, y) => println(s"1, $x , $y")
case (_, z, 5) => println(z)
case _ => println("else")
}
}
4.样例类
在Scala中样例类是一中特殊的类,可用于模式匹配。
case class是多例的,后面要跟构造参数,case object是单例的
object ScalaDemo {
def main(args: Array[String]): Unit = {
val arr = Array(SubmitTask(1, "小强"), HeartBeat(1000), CheckTimeOutTask)
arr(Random.nextInt(arr.length)) match {
case SubmitTask(id, name) => println(s"$id,$name")
case HeartBeat(t) => println(s"time:$t")
case CheckTimeOutTask => println("CheckTimeOut!")
}
}
}
case class SubmitTask(id: Int, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask
5.Option类型
在Scala中Option类型样例类用来表示可能存在或也可能不存在的值(Option的子类有Some和None)。
Some包装了某个值,None表示没有值(和Java8类似)
Option[T] 是一个类型为 T 的可选值的容器: 如果值存在, Option[T] 就是一个 Some[T] ,如果不存在, Option[T] 就是对象 None 。
当然,也可以使用getOrElse来控制默认值
def main(args: Array[String]): Unit = {
val myMap = Map("color" -> "blue")
// get返回的就是一个option类型
val v1: Option[String] = myMap.get("color")
val v2: Option[String] = myMap.get("price")
println(v1)// Some(blue)
println(v2)// None
}
6.偏函数
被包在花括号内没有match的一组case语句是一个偏函数,
它是PartialFunction[A, B]的一个实例,A代表参数类型,B代表返回类型,常用作输入模式匹配
def func1: PartialFunction[String, Int] = {
case "one" => 1
case "two" => 2
case _ => -1
}
后面调用的时候可以根据传入的值进行匹配,从而返回不同的值
更多基础相关,参考:https://www.cnblogs.com/wjcx-sqh/p/6551248.html
三、高阶函数和隐式转换
1.高阶函数
Scala混合了面向对象和函数式的特性,我们通常将可以做为参数传递到方法中的表达式叫做函数。
在函数式编程语言中,函数是“头等公民”,高阶函数包含:作为值的函数、匿名函数、闭包、柯里化等等。
作为值的函数
val fun = (x: Int) => x * 2
arr.map(fun)
匿名函数
arr.map(x => x * 2) // 可以省略类型
arr.map(_ * 2) // 可以使用神奇的下划线代表当前变量,更加简洁!,也可以使用 m1 _来将方法转换为函数
柯理化
柯里化指的是将原来接受两个参数的方法变成新的接受一个参数的方法的过程
导言:
// 定义一个方法,不过形式上看起来有点像函数
def m(x: Int) = (y:Int)=> x * y
// 给它传一个值,就变成了函数
val fun = m(2) // fun = (y:Int) => 2 * y
// 调用这个函数
fun(5) //值为10
// 一步到位,就变成了
m(2)(5)
// 这就得到了柯理化:
def m(x:Int)(y:Int) = x * y
// 可以只传一个参数:m(3)(_)
def main(args: Array[String]) { def f2(x: Int) = x * 2 val f3 = (x: Int) => x * 3 val f4: (Int) => Int = { x => x * 4 } val f4a: (Int) => Int = _ * 4 val f5 = (_: Int) * 5 val list = List(1, 2, 3, 4, 5) var new_list: List[Int] = null //第一种:最直观的方式 (Int) => Int //new_list = list.map((x: Int) => x * 3) //第二种:由于map方法知道你会传入一个类型为(Int) => Int的函数,你可以简写 //new_list = list.map((x) => x * 3) //第三种:对于只有一个参数的函数,你可以省去参数外围的() //new_list = list.map(x => x * 3) //第四种:(终极方式)如果参数在=>右侧只出现一次,可以使用_ new_list = list.map(_ * 3) new_list.foreach(println(_)) var a = Array(1,2,3) a.map(_* 3) }
2.隐式转换
简单说,隐式转换就是:当Scala编译器进行类型匹配时,如果找不到合适的候选,那么隐式转化提供了另外一种途径来告诉编译器如何将当前的类型转换成预期类型。
通过隐式转换,程序员可以在编写Scala程序时故意漏掉一些信息,让编译器去尝试在编译期间自动推导出这些信息来。
隐式的对类的方法进行增强,丰富现有类库的功能
那种以implicit关键字声明的带有单个参数的函数称为隐式转换函数
示例1:
import java.io.File
import scala.io.Source
//隐式的增强File类的方法
class RichFile(val from: File) {
def read = Source.fromFile(from.getPath).mkString
}
object RichFile {
//隐式转换方法
implicit def file2RichFile(from: File) = new RichFile(from)
}
object MainApp{
def main(args: Array[String]): Unit = {
//导入隐式转换
import RichFile._
//import RichFile.file2RichFile
println(new File("c://words.txt").read)
}
}
示例2:
import java.awt.GridLayout /** * Created by ZX on 2015/11/13. */ object ImplicitContext{ //implicit def girl2Ordered(g : Girl) = new Ordered[Girl]{ // override def compare(that: Girl): Int = if (g.faceValue > that.faceValue) 1 else -1 //} implicit object OrderingGirl extends Ordering[Girl]{ override def compare(x: Girl, y: Girl): Int = if (x.faceValue > y.faceValue) 1 else -1 } } class Girl(var name: String, var faceValue: Double){ override def toString: String = s"name : $name, faveValue : $faceValue" } //class MissRight[T <% Ordered[T]](f: T, s: T){ // def choose() = if(f > s) f else s //} //class MissRight[T](f: T, s: T){ // def choose()(implicit ord: T => Ordered[T]) = if (f > s) f else s //} class MissRight[T: Ordering](val f: T, val s: T){ def choose()(implicit ord: Ordering[T]) = if(ord.gt(f, s)) f else s } object MissRight { def main(args: Array[String]) { import ImplicitContext.OrderingGirl val g1 = new Girl("yuihatano", 99) val g2 = new Girl("jzmb", 98) val mr = new MissRight(g1, g2) val result = mr.choose() println(result) } }