我们在使用scala的时候经常会用到对象的apply方法和update方法。
虽然我们表面没有察觉,但是实际上两个方法都会遵循相关约定被调用。
apply
apply方法的约定:用括号传递给变量(对象)一个或多个参数的时候,会把它转换成对apply方法的调用。
我们先看一个例子。
class ClassApplyTest{ //类的apply方法调用示例 def apply(param:String): String ={ println("apply method called,the paramter is "+param); "Hello,world";//返回值 } } object Main{ def main(args:Array[String]): Unit ={ val myApply = new ApplyTest;//实例化ApplyTest println(myApply("param1"));//传入参数param1 } }
输出结果
apply method called,the paramter is param1
Hello,world
我们从上个例子看到,我们给ApplyTest类实例一个对象myApply,然后给myapply传入了param1的参数。
过程中并没有调用对象的apply方法,myapply对象自己调用了apply方法。
我们再看一个例子
object SingleObjectApplyTest{//单例对象的apply方法调用示例 def apply(param1:String,param2:String):String = { println("apply method called"); param1+" and "+param2; } def main(args:Array[String]): Unit ={ val myApply = SingleObjectApplyTest("zyh","zqy");
//注意,我们这里建的是单例对象不是类,并不用new关键字。 println(myApply); } }
输出结果
apply method called
zyh and zqy
我们定义了一个单例对象,并在对象中定义了apply方法。
当我们建立单例对象并传参的时候自动调用了apply方法返回了param1 and param2到了myApply。
class ClassAndObjectApplyTest{ //伴生类和对象apply方法的结合使用 } class ApplyTest{ def apply()={ println("apply method in class is called."); } def greetingFromClass = println("Greet method is called."); //没有参数的时候可以省略圆括号 } object ApplyTest{ def apply() = { println("apply method in object is called."); new ApplyTest;//返回一个ApplyTest类型的实例 } } object ClassAndObjectApplyTest{ def main(args:Array[String]): Unit ={ val myApply = ApplyTest();//ApplyTest伴生对象的调用,这里的括号一定不能省略 //注意,我们这里没有new关键字,是对ApplyTest的伴生对象的调用 //伴生对象会自动调用伴生对象的apply方法 myApply.greetingFromClass; myApply(); //ApplyTest伴生类的调用 //然后自动调用了伴生类的apply方法 } }
输出结果
apply method in object is called.
Greet method is called.
apply method in class is called.
我们这个例子包含了两对的伴生类和对象。
因为我们这里并没有任何参数,所以我们这里使用()就是向其传入参数。
我们在调用ApplyTest伴生对象并传参的时候,自动调用了ApplyTest伴生对象的apply方法,返回一个ApplyTest伴生类的一个实例对象。
我们可以通过ApplyTest伴生类的对象访问类中的方法,虽然被实例化了但是并没有传递参数,所以并没有调用其apply方法。
当我们执行myApply()的时候是对ApplyTest伴生类传参的操作,因为没有参数,所以只加了圆括号,然后自动调用其apply方法。
下面看一个scala语法中的apply的例子
val myStrArr = Array("BigDate","Hadoop","Spark");
注意到,我们在定义数组的时候,并没有像Java那样需要使用new关键字创建,
没有new实例,并不能用构造器创建,而且还直接传递了三个参数,怎么创建的呢?
其实这里,scala就会自动转换成对Array的伴生对象apply方法的调用,完成数组的建立和初始化。
update
update方法的约定:当对带有圆括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update方法。
在调用时,是把括号里的参数和等号右边的对象一起作为方法的输入参数来执行调用。
示例
val myStrArr = new Array[String](3);//声明一个长度为3的字符串数组 myStrArr(0) = "BigDate";//这里正好符合了update方法的调用规则 //调用了伴生类的Array的update方法 //执行了myStrArr.update(0,"BigDate")
从上个例子可以看出,在进行数组赋值的时候,之所以没有向java一样采用了myStrArr[0]这样的赋值的方式,
而是采用了update方法的赋值机制,为了能触发update方法的机制,所以才使用myStrArr(0)这样圆括号的形式进行赋值。