Scala比Java更面向对象的一个方面是Scala没有静态成员。替代品是,Scala有单例对象:singleton object。

当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。

定义单例对象不是定义类型(在Scala的抽象层次上说)

类和单例对象间的一个差别是,单例对象不带参数,而类可以。因为你不能用new关键字实例化一个单例对象,你没机会传递给它参数。每个单例对象都被作为由一个静态变量指向的虚构类:synthetic class的一个实例来实现,因此它们与Java静态类有着相同的初始化语法。Scala程序特别要指出的是,单例对象会在第一次被访问的时候初始化。

Scala 的apply 有2 张形式,一种是 伴生对象的apply ,一种是 伴生类中的apply,下面展示这2中的apply的使用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
class ApplyOperation {
}
class ApplyTest{
def apply(b:String) = println(b+":I am into spark so much!!!")
def haveATry: Unit ={
println("have a try on apply")
}
}
object ApplyTest{
def apply(i:Int) = {
println(i.toString+":I am into Scala so much")
new ApplyTest
}
}
object ApplyOperation{
def main (args: Array[String]) {
val array= Array(1,2,3,4)
val a = ApplyTest(111) //这里就是使用object 的使用
val b= ApplyTest.apply(222)

a.haveATry
a("AAA") // 这里就是 class 中 apply使用
b.apply("BBB")
new ApplyTest
new ApplyTest()
(new ApplyTest).apply("CCC")
// ApplyTest("DDD")--error object的apply方法参数是Int类型
//new ApplyTest(555)--error class的apply方法不是构造方法
ApplyTest(333)
ApplyTest.apply(444)
}
}

Scala<apply的几种用法>

1.只是一个快捷方式

首先定义个object:

1
2
3
4
5
6
object Greet {
def apply(name: String): Unit = {
println("Call From %s".format(name))
}
}

1
2
3
4
5
6
7
8
object Main {
def main(args: Array[String]): Unit = {
Greet.apply("Gpwner")
println("==========================")
Greet("pwner")
}
}

控制台输出:

所以当调用一个Object的时候,其实就是相当于调用了这个Object的apply方法

但是apply并不等同与构造函数

2.scala会自动为case class 生成apply方法

下面的三个操作都是一样的结果:

1
2
3
4
5
6
val p0 = new Person("Frank", 23, "Blue") // normal constructor

val p1 = Person("Frank", 23, "Blue") // this uses apply

val p2 = Person.apply("Frank", 23, "Blue") // using apply manually

3、apply应用于builder模式

一个object中的apply方法不一定要返回其自身对象,比如

1
2
3
4
5
6
7
8
case class Company(name: String)

class Person(val name: String) {}

object Person {
def apply(name: String): Company = new Company(name)
}

当调用Person的apply的时候返回的是Company对象

利用这个特点我们可以将一个类写成Builder

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
abstract class DatabaseDriver {
// some database stuff
}

object DatabaseDriver {
def apply(config: Configuration) = config.dbType match {
case "MYSQL" => new MySqlDriver()
case "PSQL" => new PostgresDriver()
case _ => new GenericDriver()
}
}

// now I get the right version!
val mydatabase = DatabaseDriver(dbConfig)

4、apply应用于匿名函数

两个语句一样的结果:

5、在class中的apply

可以在object中有apply方法,当然也在class中定义apply方法

1
2
3
4
5
6
7
8
9
10
11
class Amazing {
def apply(x: String) = "Amazing %s!".format(x)
}

// look how cool this is
val amazing = new Amazing()
amazing("world")
// => Amazing world!
amazing.apply("world")
// => Amazing world!