样例类(case class)

Scala中提供了一种特殊的类,用case class进行声明,中文也可以称作“样例类”。样例类是一种特殊的类,经过优化以用于模式匹配。样例类类似于常规类,带有一个case 修饰符的类,在构建不可变类时,Case类非常有用,特别是在并发性和数据传输对象的上下文中。示例如下:

case class Message(from:String, to:String, content:String)

一个样例类相当于一个JavaBean风格的域对象,带有getter和setter方法,以及构造器、hashCode、equals和toString方法。在创建case class的对象实例时,不需要使用new关键字。

例如,下面的代码是有效的:

val request = Message("北京","上海","高铁");

Scala更喜欢使用不变性。因此,在case类上定义的字段在默认情况下是不可变的,因此不能修改它们。如果一定要想修改case类的字段,可以在声明时使用var关键字来指定。

下面的代码定义了一个简单的样例类:

// 定义一个样例类
case class Stuff(name:String, var age:Int)

val s = Stuff("张三",45)     // 不需要使用new来实例化

println(s)

s == Stuff("张三",45)
s == Stuff("张三",43)
println(s.name)
println(s.age)

s.age = s.age + 1
println(s.age)

输出结果如下图所示:

另外,在一个样例类的定义中指定的所有输入参数不需要使用var或val修饰,Scala自动就会使用val修饰。可以从该类的外部访问它。

样例类会自动创建伴生对象。此外,Scala 添加如下四个方法到一个样例类:apply()、toString()、hashCode、equals()和copy()。这些方法使得使用一个样例类更容易。样例类对于创建不可变对象很有用。此外,它们支持模式匹配。

下面是使用case class的示例代码:

 
// 定义一个case class  
case class Money(amount:Int=1, currency:String="¥")

// 创建类的实例。注意:这里不需要用new关键字来实例化
val defaultAmount = Money()        
val fifteenYuans = Money(15,"¥")
val fifteenYuans = Money(15)
val someYuans = Money(currency="¥")
val twentyYuans = Money(amount=20,currency="¥")

// 使用copy方法构造实例:
val tenEuros = twentyEuros.copy(10)
val twentyDollars = twentyEuros.copy(currency="USD")

// ---------------------------------------------------------------
// 定义case类
case class Book(isbn: String)

// 注意:这里不需要用new关键字来实例化
val frankenstein = Book("978-0486282114")      

// 带有参数时,参数是public val类型的
case class Message(sender: String, recipient: String, body: String)
val message1 = Message("aa@qq.com", "bb@163.com", "hello?")

println(message1.sender)  // 输出aa@qq.com
message1.sender = "cc@sina.com"  // 这一行不会编译     

// 拷贝
// 可以简单地使用copy方法创建一个case类实例的浅拷贝。可以改变构造器参数(可选地)
case class Message(sender: String, recipient: String, body: String)

val message4 = Message("aa@qq.com", "bb@163.com", "good good study")
val message5 = message4.copy(sender = message4.recipient, recipient = "cc@sina.com")
message5.sender            // bb@qq.com
message5.recipient         // cc@sina.com
message5.body              // "good good study"

当一个类被声名为case class的时候,scala会帮助我们做下面几件事情:

  • 构造器中的参数如果不被声明为var的话,它默认的话是val类型的,但一般不推荐将构造器中的参数声明为var。
  • 自动创建伴生对象,同时在伴生对象里实现apply方法,使得我们在使用的时候可以不直接显示地new对象。
  • 伴生对象中同样会实现unapply方法,从而可以将case class应用于模式匹配。
  • 实现自己的toString、hashCode、copy、equals方法。

除此之此,case class与其它普通的scala类没有区别。

Scala自动为case class定义了伴生对象,也就是object,并且定义了apply()方法负责对象创建,该方法接收与主构造函数相同的参数,并返回一个case class对象。

case class是按结构比较的,而不是按引用比较。例如,在下面的代码中,尽管book1和book2引用不同的对象,但是每个对象的值是相等的:

case class Book(bookName: String, author: String)

val book1 = Book("Spark大数据处理", "xinliwei")
val book2 = Book("Spark大数据处理", "xinliwei")
     
println(book1 == book2)     // 输出值为 true

《PySpark原理深入与编程实战》