一、前言
創(chuàng)新互聯(lián)從2013年創(chuàng)立,是專業(yè)互聯(lián)網(wǎng)技術(shù)服務(wù)公司,擁有項目成都網(wǎng)站設(shè)計、網(wǎng)站制作網(wǎng)站策劃,項目實施與項目整合能力。我們以讓每一個夢想脫穎而出為使命,1280元伊美做網(wǎng)站,已為上家服務(wù),為伊美各地企業(yè)和個人服務(wù),聯(lián)系電話:18982081108
前面學(xué)習(xí)了Scala的Methods,接著學(xué)習(xí)Scala中的Object
二、Object
Object在Scala有兩種含義,在Java中,其代表一個類的實例,而在Scala中,其還是一個關(guān)鍵字,本篇首先將會把object當(dāng)成一個類的實例看待,展示如何將對象從一種類型轉(zhuǎn)化為另一種類型,之后將展示如何創(chuàng)建單例對象,Scala中還存在包對象,在Scala中,經(jīng)常有如下定義
type Throwable = java.lang.Throwable type Exception = java.lang.Exception type Error = java.lang.Error type Seq[+A] = scala.collection.Seq[A] val Seq = scala.collection.Seq
使用type定義可以使得代碼更為簡潔,可使用伴生對象來創(chuàng)建靜態(tài)方法,并且伴生對象可以使得在創(chuàng)建類對象時不需要使用new關(guān)鍵字,如下所示
val siblings = List(Person("Kim"), Person("Julia"), Person("Kenny"))
2.1 對象轉(zhuǎn)化
1. 問題描述
你需要將一個類的實例從一種類型轉(zhuǎn)化為另一種類型,如動態(tài)創(chuàng)建對象
2. 解決方案
使用asInstanceOf方法進行類型轉(zhuǎn)化,如下的lookup方法返回的對象將給轉(zhuǎn)化為Recognizer對象
val recognizer = cm.lookup("recognizer").asInstanceOf[Recognizer]
以上代碼在Java中如下
Recognizer recognizer = (Recognizer)cm.lookup("recognizer");
asInstanceOf方法是定義在Any類中的,所以任何類中都可以使用該方法
3. 討論
在動態(tài)編程中,經(jīng)常需要從一個類轉(zhuǎn)化為另一個類,如在Spring框架中使用ApplicationContext文件來初始化Bean
// open/read the application context file val ctx = new ClassPathXmlApplicationContext("applicationContext.xml") // instantiate our dog and cat objects from the application context val dog = ctx.getBean("dog").asInstanceOf[Animal] val cat = ctx.getBean("cat").asInstanceOf[Animal]
在進行數(shù)字類型轉(zhuǎn)化時,也可以使用asInstanceOf方法
當(dāng)需要與Java進行交互時,也可以使用asInstanceOf方法
val objects = Array("a", 1) val arrayOfObject = objects.asInstanceOf[Array[Object]] AJavaClass.sendObjects(arrayOfObject)
與Java類似,類型轉(zhuǎn)化可能會拋出ClassCastException異常
可以使用try/catch來解決此問題
2.2 與Java的.class對應(yīng)的方法
1. 問題描述
當(dāng)一個API需要你傳遞Class對象,在Java中,你可以使用.class,但是在Scala則行不通
2. 解決方案
使用Scala的classOf方法,如下所示
val info = new DataLine.Info(classOf[TargetDataLine], null)
在Java中則使用如下
info = new DataLine.Info(TargetDataLine.class, null);
classOf方法定義在Predef對象中,因此可以在沒有import情況直接使用
3. 討論
該方法可以讓你開始學(xué)習(xí)反射,如下示例可以訪問String類的方法
2.3 確定對象的類
1. 問題描述
在Scala中,你不需要顯示的聲明類型,你偶爾也想要打印一個對象的類或類型以明白Scala的工作機制
2. 解決方案
你可以使用對象的getClass方法來確定Scala為你自動賦值的類型,如當(dāng)需要了解可變參數(shù)的工作流程時,可以調(diào)用getClass方法,得知不同情況,類型也不相同
def printAll(numbers: Int*) { println("class: " + numbers.getClass) }
當(dāng)使用多個參數(shù)調(diào)用printAll方法和不使用參數(shù)調(diào)用printAll方法,其結(jié)果不相同
當(dāng)處理Scala的XML庫時,該方法非常有效,可以知道在不同情形下所處理的類,如下,<p>標簽下包含了一個子類
當(dāng)在<p>標簽中添加<br/>標簽后,其結(jié)果如下
3. 討論
若在IDE中無法得知對象的類型,可以使用getClass方法來獲取對象類型
2.4 使用對象啟動應(yīng)用
1. 問題描述
你想要使用main方法來啟動一個應(yīng)用,或者為腳本提供一個入口
2. 解決方案
啟動應(yīng)用有兩種方法,其一讓類繼承App,其二是定義一個對象并定義main方法
對于第一種方法,其通用做法如下
object Hello extends App { println("Hello, world") }
此時object內(nèi)的語句會自動執(zhí)行,第二種方法是定義main方法
object Hello2 { def main(args: Array[String]) { println("Hello, world") } }
3. 討論
上述兩種方法中,都是通過object來啟動應(yīng)用的
2.5 使用Object創(chuàng)建單例
1. 問題描述
你想要創(chuàng)建一個單例對象
2. 解決方案
使用object關(guān)鍵字來創(chuàng)建單例對象
object Hello2 { def main(args: Array[String]) { println("Hello, world") } }
由于CashRegister被定義為成object,因此僅僅只有一個實例,被調(diào)用的方法就相當(dāng)于Java中的靜態(tài)方法,調(diào)用如下
object Main extends App { CashRegister.open CashRegister.close }
在創(chuàng)建工具方法時,該方法同樣有效
import java.util.Calendar import java.text.SimpleDateFormat object DateUtils { // as "Thursday, November 29" def getCurrentDate: String = getCurrentDateTime("EEEE, MMMM d") // as "6:20 p.m." def getCurrentTime: String = getCurrentDateTime("K:m aa") // a common function used by other date/time functions private def getCurrentDateTime(dateTimeFormat: String): String = { val dateFormat = new SimpleDateFormat(dateTimeFormat) val cal = Calendar.getInstance() dateFormat.format(cal.getTime()) } }
由于方法是定義在object中,因此可以直接使用DateUtils來調(diào)用這些方法,如同Java中調(diào)用靜態(tài)方法
DateUtils.getCurrentDate DateUtils.getCurrentTime
在使用actors時,單例對象可以產(chǎn)生可重用的消息,如果你有可以接受和發(fā)送消息的actor,你可以使用如下方法創(chuàng)建單例
case object StartMessage case object StopMessage
這些對象將會被作為消息,并且可被傳遞到actor中
inputValve ! StopMessage outputValve ! StopMessage
3. 討論
當(dāng)使用伴生對象時,一個類就既可以有非靜態(tài)方法又可以有靜態(tài)方法
2.6 使用伴生對象創(chuàng)建靜態(tài)成員
1. 問題描述
你想要為一個類創(chuàng)建實例方法和類方法,但是Scala中沒有static關(guān)鍵字
2. 解決方案
在class中定義非靜態(tài)成員,在object中定義靜態(tài)成員,對象與類要有相同的名字并且位于同一個文件中,該對象稱為伴生對象
使用該方法可以讓你創(chuàng)建靜態(tài)成員(字段和方法)
// Pizza class class Pizza (var crustType: String) { override def toString = "Crust type is " + crustType } // companion object object Pizza { val CRUST_TYPE_THIN = "thin" val CRUST_TYPE_THICK = "thick" def getFoo = "Foo" }
Pizza類和Pizza對象在同一個文件中(Pizza.scala),Pizza對象中的成員等效于Java類中的靜態(tài)成員
println(Pizza.CRUST_TYPE_THIN) println(Pizza.getFoo)
你也可按照常規(guī)方法創(chuàng)建Pizza對象
var p = new Pizza(Pizza.CRUST_TYPE_THICK) println(p)
3. 討論
class和object具有相同的名稱并且在同一個文件中,class中定義的是非靜態(tài)成員,object中定義的是靜態(tài)成員
class和其伴生對象可以互相訪問對方的私有成員,如下面object的double方法可以訪問class中的私有變量secret
class Foo { private val secret = 2 } object Foo { // access the private class field 'secret' def double(foo: Foo) = foo.secret * 2 } object Driver extends App { val f = new Foo println(Foo.double(f)) // prints 4 }
如下的class類中的非靜態(tài)方法可以訪問伴生對象中的靜態(tài)私有變量
class Foo { // access the private object field 'obj' def printObj { println(s"I can see ${Foo.obj}") } } object Foo { private val obj = "Foo's object" } object Driver extends App { val f = new Foo f.printObj }
2.7 將常用代碼放在包對象中
1. 問題描述
你想要使方法、字段和其他代碼處于包級別,而不需要class或者object
2. 解決方案
將代碼放置在包對象下面,如將你的代碼放置在package.scala文件中,例如,如果你想要代碼被com.hust.grid.leesf.model包下所有類可用,那么創(chuàng)建一個位于com/hust/grid/leesf/model目錄下的package.scala文件,在package.scala中,在包聲明中移除model,并且以其作為名字來創(chuàng)建包,大致如下
package com.hust.grid.leesf package object model {
其他代碼放置在model中,如下所示
package com.hust.grid.leesf package object model { // field val MAGIC_NUM = 42 // method def echo(a: Any) { println(a) } // enumeration object Margin extends Enumeration { type Margin = Value val TOP, BOTTOM, LEFT, RIGHT = Value } // type definition type MutableMap[K, V] = scala.collection.mutable.Map[K, V] val MutableMap = scala.collection.mutable.Map }
此時,在com.hust.grid.leesf.model包下面類、對象、接口等可以隨意訪問上述定義的字段、方法等
package com.hust.grid.leesf.model object MainDriver extends App { // access our method, constant, and enumeration echo("Hello, world") echo(MAGIC_NUM) echo(Margin.LEFT) // use our MutableMap type (scala.collection.mutable.Map) val mm = MutableMap("name" -> "Al") mm += ("password" -> "123") for ((k,v) <- mm) printf("key: %s, value: %s\n", k, v) }
3. 討論
最疑惑的是將package對象放在哪里,其包名和對象名
如果你想要讓你的代碼在com.hust.grid.leesf.model包中可見,那么將package.scala放在com/hust/grid/leesf/model目錄下,而在package.scala中,其包名應(yīng)該如下
package com.hust.grid.leesf
然后使用model作為對象名
package object model {
最后大致如下
package com.hust.grid.leesf package object model {
包中可以存放枚舉類型、常量和隱式轉(zhuǎn)換
2.8 不使用new關(guān)鍵字來創(chuàng)建對象實例
1. 問題描述
當(dāng)不使用new關(guān)鍵字來創(chuàng)建對象時,Scala代碼會顯得相對簡潔,如下所示
val a = Array(Person("John"), Person("Paul"))
2. 解決方案
有兩種方式
為Person對象定義了伴生對象,然后定義apply方法并接受參數(shù)
class Person { var name: String = _ } object Person { def apply(name: String): Person = { var p = new Person p.name = name p } }
現(xiàn)在你可以不使用new關(guān)鍵字來創(chuàng)建Person對象了
val dawn = Person("Dawn") val a = Array(Person("Dan"), Person("Elijah"))
Scala編譯器會對伴生對象中的apply進行特殊處理,讓你不使用new關(guān)鍵字即可創(chuàng)建對象
將類定義為case類,并且接受相應(yīng)參數(shù)
case class Person (var name: String)
現(xiàn)在可以采用如下方法創(chuàng)建對象
val p = Person("Fred Flinstone")
Scala會為case類的伴生對象創(chuàng)建apply方法
3. 討論
編譯器會對伴生對象的apply做特殊處理,這是Scala的語法糖
val p = Person("Fred Flinstone")
上述代碼會被轉(zhuǎn)化為如下代碼
val p = Person.apply("Fred Flinstone")
apply方法是工廠方法,Scala的此語法糖讓你不用new關(guān)鍵字即可創(chuàng)建對象
可以在伴生對象中創(chuàng)建多個apply方法,這樣相當(dāng)于多個構(gòu)造函數(shù)
class Person { var name = "" var age = 0 } object Person { // a one-arg constructor def apply(name: String): Person = { var p = new Person p.name = name p } // a two-arg constructor def apply(name: String, age: Int): Person = { var p = new Person p.name = name p.age = age p } }
可以使用如下方法創(chuàng)建對象
val fred = Person("Fred") val john = Person("John", 42)
為了給case類創(chuàng)建多個構(gòu)造函數(shù),需要知道case類背后的邏輯
當(dāng)使用scala編譯器編譯case類時,你會發(fā)生其生成了兩個文件,Person$.class和Person.class文件,當(dāng)使用javap反編譯Person$.class文件時,其輸出如下
其包含了一個返回Person對象的apply方法
public Person apply(java.lang.String);
String對應(yīng)的是case類中的name
case class Person (var name: String)
使用javap命令可以看到在Person.class中為name生成的getter和setter函數(shù)
在如下代碼中,存在case類和apply方法
// want accessor and mutator methods for the name and age fields case class Person (var name: String, var age: Int) // define two auxiliary constructors object Person { def apply() = new Person("<no name>", 0) def apply(name: String) = new Person(name, 0) }
由于name和age都是var的,所以會生成getter和setter,在object中定義了兩個apply函數(shù),因此可以使用如下三種方式來生成Person對象
object Test extends App { val a = Person() val b = Person("Al") val c = Person("William Shatner", 82) println(a) println(b) println(c) // test the mutator methods a.name = "Leonard Nimoy" a.age = 82 println(a) }
其結(jié)果如下
Person(<no name>,0) Person(Al,0) Person(William Shatner,82) Person(Leonard Nimoy,82)
2.9 使用apply來實現(xiàn)工廠方法
1. 問題描述
為了讓子類聲明應(yīng)該創(chuàng)建哪種類型的對象,并且只在一處能夠創(chuàng)建對象,你想要實現(xiàn)工廠方法
2. 解決方案
可以使用伴生對象的apply方法來實現(xiàn)工廠方法,你可將工廠實現(xiàn)算法放置在apply方法中
假設(shè)你想要創(chuàng)建一個Animal工廠,并且返回Cat和Dog,在Animal類的伴生對象中實現(xiàn)apply方法,你就可以使用如下方式創(chuàng)建不同對象
val cat = Animal("cat") // creates a Cat val dog = Animal("dog") // creates a Dog
首先需要創(chuàng)建一個Animal的trait
trait Animal { def speak }
然后在相同文件中創(chuàng)建伴生對象,創(chuàng)建實現(xiàn)Animal的類,一個合適的apply方法
object Animal { private class Dog extends Animal { override def speak { println("woof") } } private class Cat extends Animal { override def speak { println("meow") } } // the factory method def apply(s: String): Animal = { if (s == "dog") new Dog else new Cat } }
然后就可以使用如下語句創(chuàng)建不同對象
val cat = Animal("cat") // creates a Cat val dog = Animal("dog") // creates a Dog
3. 討論
如果不使用apply方法來實現(xiàn)工廠方法,也可以使用如下的getAnimal方法來實現(xiàn)上述功能
// an alternative factory method (use one or the other) def getAnimal(s: String): Animal = { if (s == "dog") return new Dog else return new Cat }
然后可以使用如下方法創(chuàng)建不同對象
val cat = Animal.getAnimal("cat") // returns a Cat val dog = Animal.getAnimal("dog") // returns a Dog
以上兩種方法都是可行的
三、總結(jié)
本篇學(xué)習(xí)了Scala中的object及其相應(yīng)的用法,其在Scala的實際編程中應(yīng)用也是非常廣泛。
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
分享標題:Scala之Object的具體使用(小結(jié))
網(wǎng)頁路徑:http://jinyejixie.com/article6/pgehig.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供云服務(wù)器、網(wǎng)站排名、全網(wǎng)營銷推廣、網(wǎng)站導(dǎo)航、小程序開發(fā)、建站公司
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網(wǎng)站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時需注明來源: 創(chuàng)新互聯(lián)