您的当前位置:首页正文

Scala对象用法异于Java的部分

来源:花图问答

1 单例对象

scala中不提供像java那样的静态方法或静态字段,可以通过object关键字来定义一个单例对象,以此来实现和java静态方法同样的效果。

object Person {
    private var lastId = 0
    def newPerson() = {
        lastId += 1
        lastId
    }
}

上述这样一个代码块可以拿去直接运行,不必再有什么定义一个class然后再new,再调用方法。Java中的静态方法也能完成这种功能,不用实例化直接拿来用。但是scala的单例对象除了定义时使用object关键字而不是class关键字外并没有其他区别。

定义在单例对象中的字段相当于java中的静态字段,因此,字段的值是可以保留的。例如:

object Person {
    private var lastId = 0
    def newPerson() = {
        lastId += 1
        lastId
    }
printf(Person.newPersonId())
printf(Person.newPersonId())
printf(Person.newPersonId())

上述代码会依次返回1,2,3

2 伴生对象

Java中通常会用到同时包含实例方法和静态方法的类,在Scala中可以使用伴生对象来实现。
使用方法:单例对象与某个类具有相同的名称,即可称该类为“伴生对象”。类和伴生对象在同一个文件中,一般上面写class a 下面写object a。

test.scala
class Person{
    private val id = Person.newPersonId()     //类中可以直接用其伴生对象的方法
    private var name = ""
    def this(name: String) {
        this()
        this.name = name
    }
    def info() { printf("the id of %s is %d . \n",name,id)}
}

//伴生对象
object Person{
    private var lastId = 0    //静态字段
    private def newPerson() = {      //静态方法
        lastId += 1
        last
    }
    def main(args:Array[String]){
        val person1 = new Person("nsm")
        val person2 = new Person("fxl")
        person1.info   //返回 1
        person2.info   //返回 2!,因为每次都要调用Person.newPerson()这一静态方法
    }
}

实质上,伴生类Person中的成员和伴生对象Person成员都被合并在一起,并且伴生对象中的方法newPersonId()成为静态方法。可以使用scalac编译来验证,scalac编译后会发现生成了一个Person.class,里面内容如下:


3 apply与update

经常用到对象的apply和update方法,虽然表面没在用但实际很多地方被隐式地调用。

apply和update调用遵循以下约定:
用括号传递给变量(对象)一个或多个参数时,scala会把它转化成对apply方法的调用。
当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update方法,在调用时,是把括号里的参数和等号右边的对象一起作为update方法的输入参数来执行调用。

//练习class与apply用法
class TestApplyInClass {
    def apply(para:String) :String = {
        println("apply method called, param is : " + param)
        "Hello World"
    }
}
val test = new TestApplyInClass 
println(test("param1"))   //隐式的调用了class中所包含的apply方法
//练习单例对象与apply用法
object testApplyInObject{
    def apply(para1:String, para2: String): String = {
        println("apply method called")
        para1 + " and " + para2
    }
}
val test = testApplyInObject("nsm", "fxl")    //单例对象类似于静态对象,不需要实例化
println(test)

Apply方法实例:
我们在scala中初始化Array时直接可以使用val arr = Array("hadoop", "spark"),其暗中是调用了Array 半生对象(object)中的apply方法,因此scala可以直接将其传参到伴生对象中的具体方法来初始化一个数组。若想调用伴生类中的apply,必须是new一个实例a然后再使用a()来调用伴生类中的apply()方法。

update方法用法类似于apply。
以数组初始化为例看看update方法的调用方式:

//声明一个长度为3的Array,每个元素初始值为null:
val strArr = new Array[String](3)
strArr(0) = "Bigdata"   //实际上往第0个位置添加元素时使用了strArr.update(0,"Bigdata")方法

上面例子也可以解释,为什么scala不像java那样使用[ ]来表示数组位置,其原因就是引用了update方法!