- 对象 object
- 类 class
- 特质 trait
- 继承
- 样例类 case class
- 模式匹配
类: class关键字修饰,可用new class()来实例化
对象: object关键字修饰
1. 对象
1.1 单例对象
Scala中没有静态方法和静态字段,没有static,用object关键字修饰的对象是单例的,称为单例对象,静态对象。
object Singleton {
def do(msg: String) = {
println(msg)
}
}
1.2 伴生对象
伴生对象是一种特殊的单例对象。是一种相对概念,需要满足两个条件:
条件1:在同一个源文件中,
条件2:对象名和类名相同
这样的单例对象,被称作是这个类的伴生对象。类被称为是这个单例对象的伴生类。
结论:类和伴生对象之间可以相互访问私有的方法和属性
class Dog {
val id = 1
private var name = "xiaoqing"
def printName(): Unit ={println(Dog.CONSTANT + name )} //在Dog类中可以访问伴生对象Dog的私有属性
}
object Dog {
private val CONSTANT = "汪汪汪 : "
def main(args: Array[String]) {
val p = new Dog
p.name = "123"
p.printName()
}
}
1.3 apply方法
伴生对象中通常会定义apply方法,目的:不需通过new关键字,更方便的完成类和实例对象的初始化。
object ApplyDemo {
def apply(msg:String) = {
print(s"主食 油泼面,小菜:$msg")
}
def apply(i:Int):Int = { i * i }
def main(args: Array[String]) {
val arr1 = Array(5) //调用了Array伴生对象的apply方法
println(arr1.toBuffer)
println(ApplyDemo("海参炒面"))
println(ApplyDemo.apply("油炸煎饼"))
println(ApplyDemo(1))
}
}
2. 类
2.1 类的定义
Scala源文件中可以包含多个类,所有这些类都具有公有可见性。
class Student {
}
2.2 构造器
构造器分为两种:主构造器和辅助构造器
主构造器直接在类名后面定义,每个类都有主构造器,主构造器的参数直接放置类名后面,与类交织在一起。
辅助构造器自定义,使用def this关键字,而且必须调用主构造器,或者其他的辅助构造器
class Person(val name: String, val age: Int){
println("执行主构造器") //主构造器会执行类定义中的所有语句
private var gender = "male"
def this(name: String, age: Int, gender: String){ //用this关键字定义辅助构造器
this(name, age) //每个辅助构造器必须以主构造器或其他的辅助构造器的调用开始
println("执行辅助构造器")
this.gender = gender
}
var account1:String=_
def this(name:String,age:Int,gender:String){
this(name,age)
this.gender=gender
}
def this(name:String,age:Int,gender:String,account:String){
this(name,age,gender)
this.account1=account
}
println("尼玛,这里还是主构造器")
}
object Person {
def main(args: Array[String]): Unit = {
val s = new Person ("laoduan", 38) //主构造器
println(s"${s.name} ${s.age}")
val s1 = new Person (“dingding", 18, "female") //辅助构造器
println(s"${s1.gender}")
val p2 =new Person("xx2",12,"female","9527") //辅助构造器
println(s"${p2.age},${p2.account1}")
}
}
2.3 访问权限
public
:默认权限,任何地方均可访问
private
:类和其伴生对象中可访问,new出来的对象不可访问
private [this]
:当前类可访问,伴生对象无效
private [packageName]
: 指定包及其子包有效,直接写包名,不需要写路径如 private [scalaTest]即可
2.4 抽象类
abstract class Animal {
println("Animal's constructor ....")
val name: String = "animal" // 定义一个name属性
def sleep() // 没有任何实现的方法
def eat(f: String): Unit = { // 带有具体的实现的方法
println(s"$f")
}}
3 特质 Trait
Trait(特质)相当于 java的接口。
Scala的类只能单一继承,但是可以实现(继承,混入)多个特质(Trait)使用的关键字是 with
和 extends
.
特质可以定义方法体
scala可以在一个class实例化的时候动态混入trait。
trait T1 {
// 定义普通方法,有方法实现
def youcanfly()={
println("tai feng lai le you can fly")
}
}
trait T2 {
val className: String = "scala学习" // 定义一个属性
def doNothing(name: String) // 定义一个没有实现的方法,默认就是抽象方法
def doSomething() = { // 定义带有具体的实现的方法
println("简单scala")
}
}
object test{
def main(args: Array[String]): Unit = {
val t1 = new Teacher with T1 // 动态混入特征,让类有了特质的方法
println(t1.youcanfly())
val t = new Teacher() with T1 with T2{ // 动态混入特质不能使用extends关键字,可同时混入多个特质
def doNothing(name:String)={ // // 如果特质中有抽象方法,则必须重写该抽象方法,可以不使用override关键字
println(s"定义特质方法,${name}")
}
override def doSomething() = { // 重写一个有具体的实现的方法,必须使用关键字override
println("重写具体实现方法,必须写override")
}
}
println(t.teach("laozhao"))
println(t.doSomething)
println(t.youcanfly())
}
}
4. 继承
当类只实现了特质的时候,第一个关键字必须是extends
实现类还是特质,抽象方法都必须被实现,而且可以不使用override关键字
重写非抽象方法,必须使用override关键字
特质支持动态混入,在类实例化的时候,可以通过with关键字混入特质。
特质不能有构造器,抽象类可以有。
5. 样例类 case class/样例对象 case object
样例class:使用case关键字 修饰的类,重要的特征就是支持模式匹配,多例
样例object:使用case关键字修饰的对象,支持模式匹配,单例
有参数用case class,无参用case object
case class 和 class的一些区别:
1) case class在初始化的时候,不用new,而普通类初始化时必须要new。
2) case class 重写了toString方法。
3) 默认实现了equals和hashCode
4) case class 实现了序列化接口
5) case class 支持模式匹配(最重要的特征),所有case class 必须要有参数列表
case class Message(msg: String) //样例类,使用case 关键字 修饰的类, 其重要的特征就是支持模式匹配
case object CheckHeartBeat //样例object, 不能封装数据, 其重要特征就是支持模式匹配
object TestCaseClass extends App{
val msg = Message("hello") // 可以不使用new 关键字创建实例
println(msg.msg)
}
6 模式匹配
快速匹配,基本关键字为match和case
object CaseDemo01 extends App{
val arr = Array("123", "456", "777")
val name = arr(Random.nextInt(arr.length))
name match {
case "123" => println("你好这里是123")
case "456" => println("你好这里是456")
case _ => println("谢谢使用")
}
object CaseDemo02 extends App{
//val v = if(x >= 5) 1 else if(x < 2) 2.0 else "hello"
val arr = Array("hello", 1, 2.0, CaseDemo2)
val v = arr(Random.nextInt(arr.length))
println(v)
v match {
case x: Int => println("Int " + x)
case y: Double if(y >= 0) => println("Double "+ y) // if 守卫
case z: String => println("String " + z)
case CaseDemo02 => {
println("case demo 2")
}
case _ => throw new Exception("not match exception")
}
}
object CaseDemo03 extends App{
val arr = Array(1, 3, 5)
arr match {
case Array(1, x, y) => println(x + " " + y)
case Array(0) => println("only 0")
case Array(0, _*) => println("0 ...")
case _ => println("something else")
}
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, 5)
tup match {
case (2, x, y) => println(s"1, $x , $y")
case (_, z, 5) => println(z)
case _ => println("else")
}
}
case class SubmitTask(id: String, name: String)
case class HeartBeat(time: Long)
case object CheckTimeOutTask
object CaseDemo04 extends App{
val arr = Array(CheckTimeOutTask, HeartBeat(12333), SubmitTask("0001", "task-0001"))
arr(Random.nextInt(arr.length)) match {
case SubmitTask(id, name) => {
println(s"$id, $name")
}
case HeartBeat(time) => {
println(time)
}
case CheckTimeOutTask => {
println("check")
}
}
}
object PartialFuncDemo {
def func1(num: String) : Int = num match {
case "one" => 1
case "two" => 2
case _ => -1
}
def func2: PartialFunction[String, Int] = { //偏函数,它是PartialFunction[A, B]的一个实例,A代表输入参数类型,B代表返回类型,常用作输入模式匹配
case "one" => 1
case "two" => 2
case _ => -1
}
def main(args: Array[String]) {
println(func1("one"))
println(func2("one"))
}
}
object PartialFunctionDemo2 {
def f:PartialFunction[Any,Int]={
case i:Int => i *10
case _ => i *10
}
def main(args: Array[String]): Unit = {
val arr = Array(1,3,5,"seven")
val collect: Array[Int] = arr.collect {
case t: Int => t * 10
}
println(collect)
arr.collect(f).foreach(println) //偏函数最常用的就是方法中要求传入偏函数的类型。
}
}
总结
类和对象:object无构造器,必须是无参的,对象本质拥有类的所有特性,如果不需要构造器封装数据,优先使用object
特质和抽象类:
1)优先使用特质,一个类可以扩展多个特质,但却只能扩展一个抽象类。
2)如果需要构造方法,使用抽象类。因为抽象类可以定义带参数的构造器,而特质不行