Scala面向对象
类
首先介绍一下一个常用的符号_
在Scala中,下划线 _
有多种用法,取决于上下文。以下是一些常见用法:
-
通配符(Wildcard): 在模式匹配中,可以使用下划线作为通配符,表示任何值。
val list = List(1, 2, 3, 4, 5) list match { case _ :: rest => println(s"The rest of the list: $rest") case _ => println("Empty list") }
在这个例子中,
_ :: rest
匹配非空列表的头部,而下划线表示我们对头部的值不感兴趣。 -
匿名函数参数: 在匿名函数中,可以使用下划线作为参数占位符。
val addOne: Int => Int = _ + 1 println(addOne(5)) // 输出 6
在这里,
_
代表函数参数。 -
占位符语法(Placeholder Syntax): 在某些上下文中,可以使用下划线来代替一个或多个参数,根据上下文推断。
val numbers = List(1, 2, 3, 4, 5) val squares = numbers.map(_ * _)
在这个例子中,
_ * _
表示一个函数,它接受两个参数并返回它们的乘积。 -
部分应用函数: 下划线还可用于部分应用函数,其中使用下划线占位符表示未指定的参数。
def add(x: Int, y: Int): Int = x + y val add2 = add(2, _: Int) println(add2(3)) // 输出 5
在这里,
add(2, _: Int)
创建了一个部分应用函数,表示将2
绑定到x
,而y
仍然是一个待定的参数。
import scala.beans.BeanProperty
object Main {
def main(args: Array[String]): Unit = {
var s1=new Student("男","123456")
var s2=new Student(1,"scala",12,"男","123456")
println(s1.toString)
println(s2.toString)
println(s2.getSex)
}
}
class Student(var id: Int,var name: String,var age: Int){ // 主构造函数
@BeanProperty protected var sex:String = _ // 占位符
@BeanProperty protected var phone:String = _ // 注解创建get,set方法,只能获取非private的字段
def this(sex:String,phone:String){ // 辅助构造函数
this(0,"###",0) // 必须先调用主构造函数
this.sex=sex
this.phone=phone
}
def this(id: Int,name: String,age: Int,sex: String, phone: String) {
this(id,name,age)
this.sex = sex
this.phone = phone
}
override def toString: String = s"id=${id} name=${name} age=${age} sex=${sex} phone=${phone}"
}
scala类的注意点
- Scala中的所有属性默认为public
- 不同于java,Scala的类声明没有public,基本格式为class 类名{},如果是空类的话则直接写calss 类型即可
- 类的属性的默认值可用_作为占位符,但是在构造器中的默认值不能使用_
- Scala中的类都可以有一个主构造器和多个辅助构造器,这些构造器的参数可以带默认值
- 主构造器里面的参数声明必须带val/var修饰,这样才表示属性可以在类外面的调用,如果不带修饰的话,则只是主构造器的参数,则只能在类里面使用而不表示具体的属性,而辅助构造函数里面的参数必须是原本类里面就定义了的属性可以是主构造函数里面的
- 辅助构造器的使用里面必须先调用主构造器
对象
单例对象
在 Scala 中,单例对象是通过 object
关键字来创建的。单例对象是一种特殊的对象,只有一个实例,可以包含静态方法、静态字段以及其他与类关联的方法和字段。单例对象通常被用作工具类、工厂方法,或者是不需要实例化的类的替代。这里的单例对象相当于一个静态类,Scala中没有static修饰符,一半用object创建一个单例对象作为静态类全局使用,只会加载一次。
伴生对象
在Scala中,伴生对象是与类同名且定义在同一个文件中的对象。伴生对象和类之间可以相互访问对方的私有成员,它们通常一起用于实现某种模式或提供类相关的静态方法。以下是关于Scala伴生对象的一些要点:
-
名称相同: 伴生对象的名称必须与其关联的类的名称相同。
-
共享访问权限: 伴生对象和类之间共享其成员的访问权限。例如,一个类的私有成员可以在其伴生对象中访问,反之亦然。
-
静态方法: 伴生对象通常包含类级别的静态方法。这些方法可以通过类名直接调用,而不需要创建类的实例。
-
工厂方法: 伴生对象常用于实现工厂方法,这是一种创建类实例的方式,有时会比使用构造函数更灵活。
-
apply方法: Scala中的伴生对象通常包含一个
apply
方法,该方法用于创建类的实例。这使得可以使用类似函数调用的语法来创建对象。 -
伴生类和伴生对象的生命周期: 伴生类和伴生对象在同一个编译单元中,它们共享相同的生命周期。
其实一个类和其伴生对象就是一个类分别为该类的动态部分和静态部分,Java编译中也是编译为一个类,因此伴生对象可以访问类里面的所有属性包括私有属性。
apply方法: 伴生对象的apply
方法主要用于创建类的实例。当你在伴生对象上调用类名和参数时,实际上是在调用apply
方法。这使得可以使用更简洁的语法来创建对象。
unapply方法: unapply
方法是提取器的一部分,用于将对象的值分解为其组成部分。它通常与match
语句结合使用,以模式匹配的方式检查和提取对象的属性。】
import scala.beans.BeanProperty
object Main {
def main(args: Array[String]): Unit = {
val s1=new Student("name1",11)
val s2=Student.apply("name2",12) // 伴生对象创建对象
val s3=Student("name3",13)
val s4=Student.unapply(s3)
println(s1.toString)
println(s2.toString)
println(s3.toString)
println(s4)
}
}
class Student(private var name:String,private var age:Int){
override def toString: String = s"name : ${name} age : ${age}"
}
object Student{
def apply(name:String,age:Int): Student = new Student(name,age)
def unapply(arg: Student): Option[(String,Int)] = Some(arg.name,arg.age)
}
/*
在Scala中,Some 是一个表示某个值存在的容器类,通常用于与 Option 类一起使用。Option 是 Scala 标准库中的一个容器类型,表示可能存在也可能不存在的值。
*/
样例类和样例对象
样例类(Case Class):
-
不可变性(Immutability):样例类是不可变的,一旦创建,其属性值不能被修改,因此样例类必须要有构造方法。
-
自动创建伴生对象:编译器会自动生成一个与样例类同名的伴生对象,该伴生对象包含了一些便捷的方法,如apply、unapply等。
-
默认实现toString、equals和hashCode方法:编译器会自动生成这些方法,使得样例类的实例在打印和比较时更加直观和方便。
-
模式匹配:样例类是模式匹配的理想候选,因为它们天生支持模式匹配,可以轻松地用于模式匹配表达式中。
-
便捷的属性访问:样例类的构造参数会自动成为类的属性,并且可以直接通过名称访问。
样例对象(Case Object):
-
单例实例:样例对象是单例的,即在应用程序中只有一个实例存在。
-
伴生对象自动创建:与样例类一样,编译器会自动生成一个与样例对象同名的伴生对象,包含一些常用的方法。
-
模式匹配:由于是单例,样例对象也适用于模式匹配,并且不需要担心实例化的问题。
-
用于表示不可变的值:样例对象通常用于表示不可变的、唯一的值,比如枚举值或某个配置的单一实例。
Scala中的样例类类和样例对象默认实现类序列化
object Main {
def main(args: Array[String]): Unit = {
val s1=new Student("name1",11)
val s2=Student.apply("name2",12)
val s3=Student("name3",13)
val s4=Student.unapply(s3)
println(s1.toString)
println(s2.toString)
println(s3.toString)
println(s4)
}
}
case class Student(private var name:String,private var age:Int)
抽象类和特质
抽象类(Abstract Class):
-
定义:抽象类是一个可以包含抽象(没有完整实现)和非抽象方法的类,可以使用
abstract
关键字定义抽象类,可以包含抽象和非抽象方法。 -
单继承:一个类只能继承一个抽象类。
-
构造函数:抽象类可以有构造函数,并且可以有参数。
-
字段:抽象类中可以有字段,字段可以是抽象的或具体的。
-
构造顺序:抽象类的构造函数在子类之前执行。
特质(Traits):
-
定义:特质是一种类似于 Java 接口的机制,可以包含抽象和非抽象方法。使用
trait
关键字定义特质。 -
多继承:一个类可以混入多个特质。
-
构造函数:特质不能直接拥有构造函数,但可以包含被混入类使用的构造方法。
-
字段:特质中的字段不能包含参数。
-
构造顺序:特质的构造方法在被混入类的构造方法之前执行。
extends
继承,with
作为多个特质的连接
object Main {
def main(args: Array[String]): Unit = {
ZhangSan.show
ZhangSan.Ado
ZhangSan.Bdo
}
}
abstract class Student{
def show
}
trait A{
def Ado
}
trait B{
def Bdo={
println("执行B")
}
}
object ZhangSan extends Student with A with B{
override def show: Unit = {
println("我是张三")
}
override def Ado: Unit = {
println("执行A")
}
}
Type
在 Scala 中,type
关键字用于给类型起别名,称为类型别名。
type TypeName = ExistingType