網(wǎng)站做下載功能網(wǎng)站代搭建維護(hù)
1 單例對(duì)象
在編寫 Java 程序時(shí),我們經(jīng)常會(huì)通過編寫靜態(tài)方法代碼,去封裝常用的 Utility 類。
在 Scala 中沒有靜態(tài)成員這一概念,所以,如果我們要定義靜態(tài)屬性或方法,就需要使用 Scala 的單例對(duì)象 object。Scala 的對(duì)象跟 Javascript 中定義一個(gè)對(duì)象,概念是差不多的。
下面定義一個(gè)球員對(duì)象,并在 main
函數(shù)打印球員對(duì)象的相關(guān)屬性:
/*** 球員對(duì)象*/
object FootballPlayerObject {/*** 姓名*/var NAME: String = "Mohamed Salah"/*** 年紀(jì)*/var AGE: Int = 31/*** 所在俱樂部*/var CLUB: String = "Liverpool"/*** 定義入口 main 函數(shù),打印球員對(duì)象相關(guān)屬性* @param args*/def main(args: Array[String]): Unit = {System.out.println(FootballPlayerObject.NAME)System.out.println(FootballPlayerObject.AGE)System.out.println(FootballPlayerObject.CLUB)}
}
2 工具類案例
我們可以利用單例對(duì)象實(shí)現(xiàn)工具類,例如,下面實(shí)現(xiàn)了一個(gè)簡(jiǎn)易的 DateUtils
import org.joda.time.format.DateTimeFormat/*** 日期時(shí)間工具類*/
object DateUtils {val TIME_FORMAT = DateTimeFormat.forPattern("yyyy-MM-dd HH:mm:ss")/*** 判斷一個(gè)時(shí)間是否在另一個(gè)時(shí)間之前** @param time1 第一個(gè)時(shí)間* @param time2 第二個(gè)時(shí)間* @return 判斷結(jié)果*/def before(time1: String, time2: String): Boolean = {TIME_FORMAT.parseDateTime(time1).isBefore(TIME_FORMAT.parseDateTime(time2))}/*** 判斷一個(gè)時(shí)間是否在另一個(gè)時(shí)間之后** @param time1 第一個(gè)時(shí)間* @param time2 第二個(gè)時(shí)間* @return 判斷結(jié)果*/def after(time1: String, time2: String): Boolean = {TIME_FORMAT.parseDateTime(time1).isAfter(TIME_FORMAT.parseDateTime(time2))}/*** 計(jì)算時(shí)間差值(單位為秒)** @param time1 時(shí)間1* @param time2 時(shí)間2* @return 差值*/def minus(time1: String, time2: String): Int = {((TIME_FORMAT.parseDateTime(time1).getMillis - TIME_FORMAT.parseDateTime(time2).getMillis) / 1000).toInt}def main(args: Array[String]): Unit = {println(DateUtils.before("2023-01-01 00:00:00", "2024-01-01 00:00:00"))println(DateUtils.after("2023-01-01 00:00:00", "2024-01-01 00:00:00"))println(DateUtils.minus("2024-01-01 00:00:00", "2023-01-01 00:00:00"))}
}
運(yùn)行后,控制臺(tái)打印:
true
false
31536000
3 伴生對(duì)象
如果想一個(gè)類,既需要靜態(tài)成員,又需要實(shí)例成員,在 Scala 中可以使用伴生對(duì)象(companion object
)來實(shí)現(xiàn)。
3.1 伴生對(duì)象的定義
伴生對(duì)象有以下特點(diǎn):
(1) 伴生對(duì)象 和 類 必須要在同一個(gè) class 文件中。
(2) 伴生對(duì)象名字要和類名字一致。
(3) 伴生類 和 伴生對(duì)象可以互相訪問彼此的 private
屬性。
/*** 球員信息類*/
class PlayerInfo(private var playerName: String, var age: Int, var club: String) {def hello(): String = {s"Hey buddy, I am ${this.playerName} of ${this.club}, ${this.age} years old!"}
}/*** PlayerInfo 類的共生對(duì)象*/
object PlayerInfo {/*** 定義球員夢(mèng)想*/private var dream: String = "The dream of %s is achieving World Cup"/*** 打印球員夢(mèng)想*/def myDream(playerName: String): String = {String.format(this.dream, playerName)}/*** main 方法* @param args*/def main(args: Array[String]): Unit = {// 定義球員信息對(duì)象val player: PlayerInfo = new PlayerInfo("Erling Haaland", 23, "Manchester City F.C.")println(player.hello())// 執(zhí)行共生對(duì)象的 myDream 方法// 可以訪問共生類的私有 playerNameprintln(this.myDream(player.playerName))}
}
3.2 apply 及 unapply 方法
在 Scala 中,apply
和 unapply
是兩個(gè)特殊的方法,它們通常與伴生對(duì)象一起使用,并且在模式匹配、構(gòu)造對(duì)象等方面發(fā)揮著重要作用。
3.2.1 apply 方法
apply
方法通常用于對(duì)象的構(gòu)造。當(dāng)你調(diào)用類似 ClassName(args) 的代碼時(shí),實(shí)際上是調(diào)用了類的伴生對(duì)象的 apply
方法。這使得你可以像調(diào)用函數(shù)一樣構(gòu)造對(duì)象,而不需要顯式地使用 new 關(guān)鍵字。
例如,我們?cè)诙x一個(gè)列表時(shí),并不需要使用 new
: val list = List(1, 2, 3)
,下面為球員信息類的共生對(duì)象定義了 apply
方法:
/*** 球員信息類*/
class PlayerInfo(private var playerName: String, var age: Int, var club: String) {def hello(): String = {s"Hey buddy, I am ${this.playerName} of ${this.club}, ${this.age} years old!"}
}/*** PlayerInfo 類的共生對(duì)象*/
object PlayerInfo {/*** 定義球員夢(mèng)想*/private var dream: String = "The dream of %s is achieving World Cup"/*** 打印球員夢(mèng)想*/def myDream(playerName: String): String = {String.format(this.dream, playerName)}/*** 定義 apply 方法,新建一個(gè) PlayerInfo 對(duì)象** @param playerName 球員名稱* @param age 年齡* @return {@link PlayerInfo} 對(duì)象*/def apply(playerName: String, age: Int): PlayerInfo = new PlayerInfo(playerName, age, "Manchester City F.C.")/*** main 方法* @param args*/def main(args: Array[String]): Unit = {// 定義球員信息對(duì)象,有了 apply 方法后,不再需要 new 關(guān)鍵字val player: PlayerInfo = PlayerInfo("Erling Haaland", 23)println(player.hello())// 執(zhí)行共生對(duì)象的 myDream 方法// 可以訪問共生類的私有 playerNameprintln(this.myDream(player.playerName))}
}
3.2.2 unapply 方法
unapply
方法通常用于模式匹配。它是 Extractor
模式的一部分,允許你從對(duì)象中提取部分信息,并將其與模式進(jìn)行匹配。
例如:
/*** 球員信息類*/
class PlayerInfo(private var playerName: String, var age: Int, var club: String) {def hello(): String = {s"Hey buddy, I am ${this.playerName} of ${this.club}, ${this.age} years old!"}
}/*** PlayerInfo 類的共生對(duì)象*/
object PlayerInfo {/*** 定義 apply 方法,新建一個(gè) PlayerInfo 對(duì)象** @param playerName 球員名稱* @param age 年齡* @return {@link PlayerInfo} 對(duì)象*/def apply(playerName: String, age: Int): PlayerInfo = new PlayerInfo(playerName, age, "Manchester City F.C.")/*** 定義 unapply,作為提取器,提取球員 姓名,年齡,俱樂部* @param playerInfo 球員信息對(duì)象* @return*/def unapply(playerInfo: PlayerInfo): Option[(String, Int, String)] = Some(playerInfo.playerName, playerInfo.age, playerInfo.club)/*** main 方法* @param args*/def main(args: Array[String]): Unit = {// 定義球員信息對(duì)象,有了 apply 方法后,不再需要 new 關(guān)鍵字val player: PlayerInfo = PlayerInfo("Erling Haaland", 23)player match {case PlayerInfo(name, age, club) => println(s"name: ${name}, age: ${age}, club: ${club}")case _ => println("Not matched")}}
}
在上面的代碼中,unapply
方法從 PlayerInfo
對(duì)象中提取了名字、年齡和俱樂部,并將它們作為元組返回。在 match
表達(dá)式中,case PlayerInfo(name, age, club)
部分使用了模式匹配,它調(diào)用了 PlayerInfo
伴生對(duì)象的 unapply
方法來提取 PlayerInfo
對(duì)象的信息,并與模式中的名字、年齡和俱樂部進(jìn)行匹配。