伴生类和伴生对象
设计初衷
由于static定义的类和对象破坏了 面向对象编程的规范完整性,因此scala 在设计之初就没有static关键字概念,类相关的静态属性都放在伴生对象object中。
简单理解:object就是java中的static部分,定义的是类中静态属性。
概念
当同一个文件内同时存在
object x
和class x
的声明时:
- 我们称
class x
称作object x
的伴生类。- 其
object x
称作class x
的伴生对象。其中伴生类和伴生对象需要同名。
在Scala里,类和伴生对象之间没有界限——它们可以互相访问彼此的private字段和private方法。
编译方式
在编译时,伴生类
object x
被编译成了x.class
,而伴生对象
object x
被编译成了x$.class
。
创建语法
伴生对象中的属性可以直接使用类名进行调用;伴生类中的属性,需要先实例化对象,才能够进行调用。
没有class,只有object则是单例模式类。
scala中伴生类&伴生对象的语法如下:
class AssociatedDemo {
val a:Int = 10;
var b:Int = 2;
}
object AssociatedDemo{
val object_v1:String = "变量1";
def main(args: Array[String]): Unit = {
// 注:只有伴生对象中可以定义主函数,类似于static修饰
println("伴生对象变量:" + AssociatedDemo.object_v1);
println("伴生类变量:" + (new AssociatedDemo()).a);
}
}
输出结果:
伴生对象变量:变量1
伴生类变量:10
apply()
apply()是一个语法糖,直接调用类(对象)名称时候,默认执行的是该类(对象)的apply()方法。
目的是为了适应函数式编程的编码规范,可以在伴生对象的apply()中new一个对象,使用案例如下:
object AssociatedDemo{
def apply():AssociatedDemo = new AssociatedDemo();
def main(args: Array[String]): Unit = {
// 变量复制,直接可以实例化对象,不需要再new了
val ad1 = AssociatedDemo();
}
}
demo
class apply() & object apply()的代码案例如下:
class AssociatedDemo {
// class中的apply()方法
def apply(param:String){
println("class apply method called:" + param)
}
}
object AssociatedDemo{
// object中的apply()方法
def apply(param:String){
println("object apply method called:" + param)
}
def main(args: Array[String]): Unit = {
// class 的apply()
val ad2 = new AssociatedDemo();
ad2("AAA")
ad2("BBB")
// object 的apply()
AssociatedDemo("CCC")
AssociatedDemo("DDD")
}
}
Demo执行结果
class apply method called:AAA
class apply method called:BBB
object apply method called:CCC
object apply method called:DDD
case class
案例类(case class)和普通类本质没有不同,适合用于属性不可变的类。
case class中默认有
apply()
来负责对象的创建,不需要new
来实例化。
类似于Java 开发中的entity类,属于一种特殊的类,其中属性不可变,且均为public。
定义方法
案例类在比较的时候是按值比较而非按引用比较,Demo如下:
case class Message(sender: String, recipient: String, body: String)
val message2 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val message3 = Message("jorge@catalonia.es", "guillaume@quebec.ca", "Com va?")
val messagesAreTheSame = message2 == message3 // true
尽管message2
和message3
引用不同的对象,但是他们的值是相等的,所以message2 == message3
为true
。
case object
没有参数的case
类将被声明为case
对象而不是case
类。 默认情况下,case
对象是可序列化的。
case class CaseClass2(a:Int) extends SuperTrait // Case class
case object CaseObject extends SuperTrait // Case object
Match匹配
case class 和 case object可以和match配合使用,Demo如下:
// 定义案例类
abstract class Notification
case class Email(sender: String, title: String, body: String) extends Notification
case class SMS(caller: String, message: String) extends Notification
case class VoiceRecording(contactName: String, link: String) extends Notification
// match匹配对象类型
def showNotification(notification: Notification): String = {
notification match {
case Email(sender, title, _) => "Email"
case SMS(number, message) => "SMS"
case VoiceRecording(name, link) => "VoiceRecording"
}
}
参考资料
- Scala之:伴生对象与静态概念 - 掘金 (juejin.cn)
- 《Scala程序设计:Java虚拟机多核编程实战》
- 案例类(Case Classes) | Scala Documentation (scala-lang.org)