Scala-apply方法
Scala是一种构建在JVM之上的静态类型脚本语言,而脚本语言会有一些约定来增强灵活性,下面看两条在日常开发中常见的约定:
约定1:在明确了调用者的前提下,若方法只有一个参数,则调用时就可以省略点及括号,例如
0 to 2
的完整调用是0.to(2)
,但是println(10)
就不能简写成println 10
,因为没有明确方法的调用者。
约定2:用括号给一个变量(对象)传递参数时,scala会把它转换成对apply方法的调用。
apply方法可以定义在class中,也可以定义在object中,这两种方式有所区别,但本质是一样的,下面列举一个简单是示例来说明apply方法的用法。
- 在class中定义apply方法
class ApplyTest{
def apply() = println("I am into spark so much!!!")
def apply(p: String) = println("apply with one param:" + p)
def haveATry: Unit ={
println("have a try on apply")
}
}
object ApplyOperation{
def main (args: Array[String]) {
val array= Array(1,2,3,4)
val a = new ApplyTest()
a.haveATry
a() //调用无参apply
a("adsffdsa") //调用带参数的apply
}
}
根据约定,我们用括号想对象中传递参数,scala编译器会将其转换成对apply方法的调用,需要注意的是class中的apply方法指向具体的对象。
编译后的部分代码如下:
public final class ApplyOperation$
{
public static final MODULE$;
static
{
new ();
}
public void main(String[] args)
{
int[] array = { 1, 2, 3, 4 };
ApplyTest a = new ApplyTest();
//此处是关键
a.haveATry();
a.apply();
a.apply("adsffdsa");
}
private ApplyOperation$() { MODULE$ = this;
}
}
- 在object中定义apply方法
在前面讲过,被object定义出来的是一个static final
的单例对象,那么一个被定义在object中的apply方法与这个单例对象之间有什么联系呢?先看代码示例
class ApplyTest{
def apply() = println("I am into spark so much!!!")
def apply(p: String) = println("apply with one param:" + p)
def haveATry: Unit ={
println("have a try on apply")
}
}
object ApplyTest {
def apply(a: String, b: String) = {
println(a + ",," + b)
}
}
object ApplyOperation{
def main (args: Array[String]) {
val a = ApplyTest("s","n")
}
}
由于ApplyTest是一个单例对象,所以,按照约定,用括号向对象中传递参数时,会调用apply方法。对于上面的示例,就是在单例对象ApplyTest
上调用apply(a,b)方法,可以通过编译后的源码来验证这一点
import scala.runtime.BoxedUnit;
public final class ApplyOperation$
{
public static final MODULE$;
static
{
new ();
}
public void main(String[] args)
{
//此处是重点
ApplyTest..MODULE$.apply("s", "n"); BoxedUnit a = BoxedUnit.UNIT;
}
private ApplyOperation$() { MODULE$ = this;
}
}
从上面的代码中可以看出,确实是在单例对象 MODULE$上调用的apply方法。