1. scala class与object二次理解(函数定义上理解)
使用上理解为,object中的方法,在其他地方可以通过类名.方法的方式使用,可以认为object中的方法,都是静态方法。但是,实际上是,他们都是普通方法,这些object中的方法,其实是伴生类中的实例方法,之所以可以通过类名.方法,则是因为伴生类中有个静态实例,外部调用这些方法,编译的时候,是编译成获取到静态实例,然后通过静态实例去调用方法。
在伴生类中,定义的方法,则里面的方法,是在object名字对应的class中,这个class才是最终使用的。总之,是object和class共同组成了一个完整的类object同名,这个类中静态方法,有普通方法等。外部使用静态方法,在是object生成的伴生类提供作用。
package cn.chapter3_function
/**
* 1.函数定义的方式:
* scala的设计者任务static静态方法不符合面向对象的方式,所以在底层上,把这种替换static方法
* 全部都生成了伴生类中的普通方法,在object中定义的方法,可以使用类名.方法去定义,但是,实际上
* 是符合面向对象的,因为,把所有的object的中的方法,都是在伴生类中定义的,调用方式也是通过一个
* 静态对象去实现的调用伴生类内部的方法,本质上还是对象之间的方法调用,而不是静态之间的调用。
*2.伴生类与伴生对象二次理解:
* Fun1_def.funcName2("s") //funcName2定义在object中
* new Fun1_def().funcName("ss") //定义在class中
*
* //反编译之后
* Fun1_def$.MODULE$.funcName2("s"); object的方法,通过伴生类的实例对象用
* new Fun1_def().funcName("ss"); class的方法,通过new object的class实现。
* 2.1:Object中定义的方法,编译之后,全部在伴生类中间实现,外部直接类名.方法名(funcName2d在object中)调用,
* 则是通过Fun1_def$.MODULE$.funcName2("s");本质上,还是使用伴生类实例的方法。
* 2.2:object才是大头,在class中的方法,都是在object中创建的,使用对象也是object new出来的,伴生类就是用来
* 存储object中的静态方法的,其余的没什么用处了。以后使用的时候,就创建一个object,在他的class下,写语句,这些
* 语句最终属于object。
* 2.3: 这样做的好处是,static方法不存在了,都是普通的方法,方法的调用都是通过实例实现的。
*
*/
class Fun1_def {
def funcName(param1: String): Int = {
println("class定义函数:输出函数参数值" + param1)
return 1
}
}
object Fun1_def {
def main(args: Array[String]): Unit = {
//2.定义在这个位置的函数,是伴生类定义的私有方法,函数名是$1,在原有基础之上。
def funcName(param1: String): Int = {
println("object中main方法中:输出函数参数值2" + param1)
return 1
}
val fun1_def = new Fun1_def()
fun1_def.funcName("zs")
funcName2("name")
}
//1.通用格式,定义在object的函数,就是静态方法,直接类型.方法名都可以调用了。
def funcName2(param1: String): Int = {
println("object定义函数:输出函数参数值" + param1)
return 1
}
}
2. 方法的定义与返回值
def 方法名(参数名 : 参数类型, .... ) : 返回类型 = { 方法体 }
对于返回值,可以不写返回类型,会自动推断出来。如果返回Unit,则可以不用写=。
package cn.chapter3_function
/**
* 方法返回值。记住返回Unit三种函数声明
*/
object Fun2_return {
def main(args: Array[String]): Unit = {
}
//1. 单行函数,可以不加大括号
def fun1() = println()
//2.当不添加函数返回值时,会自动进行类型推导,如果不加=,则无返回值
def fun2() = {
""
}
//对于函数的返回值为Unit的时候,即不需要函数返回值的时候,称为过程:
def fun3(): Unit = {
println("过程函数定义1: 返回值为Unit")
}
def fun4() = {
println("过程函数定义2: 不写返回值,也不返回任何数值")
}
def fun5() {
println("过程函数定义3: 不写=号,则默认的返回值就是Unit")
}
}
3. 函数参数
- 默认参数,在类型后添加默认值,调用时,可以不用写。
- 带名参数,定义了多个默认参数,可以通过参数名单独指定某个参数的值。
- **问题:**如果定义一个含有默认参数方法,和该函数的重载方法冲突了,则优先使用重载方法。
def fun1(){} 和 def fun1(name : String='zs')
. - 可变参数: 在参数类型后添加 *, 实现原理是,参数的类型是seq[String]。
- 序列如何在可变参数中使用,格式 `seq(1,2,3): _* .
package cn.chapter3_function
/**
* 函数3: 参数值
* 1.默认参数,在参数的类型加上默认参数值,调用可以不用填写参数值。
* 如果给出的参数不够,则会从左到右依次应用参数。
* 2.带名参数:如果有多个默认参数,则通过指定参数名的方式赋值。
* 3.如果含有方法重载,和方法默认值冲突,则优先调用重载的方法。
* 4.可变参数的定义,在类型上添加*,本质原理是参数类型是序列。
* 5.对于一个可变参数,如果序列向传入当参数,需要将序列单独遍历出来,当参数传进去。
* seq : _* 这种操作。(反编译看不懂实现原理)
*/
object Fun3_param {
def main(args: Array[String]): Unit = {
fun1("zs", 29)
/* 最终对于默认参数的调用方式。
int x$1 = 19;
String x$2 = fun2$default$1();
fun2(x$2, x$1);
public int fun1$default$2()
{
return 10;
}
*/
fun2(age = 19)
//fun2方法有两个,使用这个参数,可以符合fun2(name,age)参数有默认值,和fun2(name),这个
//则会优先匹配参数个数匹配的方法。
fun2("zs")
//4.定义了可变参数,使用普通参数调用。
val zs: Int = fun3("zs", "ls", "ww")
println("fun3结果返回值" + zs)
//5.对于可变参数函数,参数类型不能是序列类型。因为接受和传递的参数类型都是不一致的。可以
//将序列的值遍历出来,一个个传入进去
fun3(Seq[String]("zs2", "ls2", "ww2"): _*)
}
//1.函数使用默认参数,可以在调用的时候,不指定这个参数的值。
def fun1(name: String, age: Int = 10): Unit = {
println(s"姓名是${name},age是${age}")
}
//2.函数中含有多个默认参数,如果想给单独参数赋值,通过属性名指定。
def fun2(name: String = "zs", age: Int = 10): Unit = {
println(s"姓名是${name},age是${age}")
}
//3.方法重载时,如果有默认参数,如何区分。会优先使用重载函数u.
def fun2(name: String): Unit = {
println(s"姓名是${name}")
}
//4.定义可变参数,在方法名的类型上添加*,同样可变参数必须在最后。
//public int fun3(Seq<String> name),原理和java一样,都是数组,这个是序列。可以对参数进行序列的操作。
def fun3(name: String*): Int = {
for (s <- name) {
println(s)
}
name.length
}
}
4. 案例 (定义可变参数函数,使用递归实现求和)
package cn.chapter3_function
/**
* 函数案例:递归实现序列累加
*/
object Fun4_example {
def main(args: Array[String]): Unit = {
val i: Int = sum(1, 2, 3)
println(i)
}
/**
* 定义一个函数,递归实现序列累加:
* 第一个值,加上后面所有尾巴的值。
* seq.tail: 截取序列,除了第一个值。
*
* @param seq
* @return
*/
def sum(seq: Int*): Int = {
if (seq.length == 0) {
0
} else {
seq.head + sum(seq.tail: _*)
}
}
}