无参方法的惯例是:
- 方法没有参数。
- 方法不会改变可变状态(无副作用)
这个惯例支持统一访问原则(uniform access principle): 客户代码不应由属性是通过字段实现还是方法实现而受影响。
父类中定义的无参函数(def) ,子类可以用一个字段来实现(val/var)
比如:
abstract class A { def a : Int;}
子类可以为:
class B extends A { val a = 1 } //里面的val也可以写成var
当然val成员也可以在子类中被override
class A { val a = 2 }
class B extends A { override val a = 3 }
但父类中成员声明为var则子类用val重写是不行的,因为var提供了getter/setter,而val只有getter:
abstract class A { var a:Int }
class B extends A { val a = 1}
error: class B needs to be abstract, since variable a in class A of type Int is not defined (Note that an abstract var requires a setter in addition to the getter)
如果一个类中,出现了同名的 成员变量和无参函数,则编译时会报错(有参则没有问题),这点与java不同。
java中有4个命名空间:
- 包
- 类型
- 方法
- 字段
方法与字段是不同的命名空间,所以字段与方法同名是不会冲突的。
而scala中仅有2个命名空间:
- 值(字段/方法/包/单例)
- 类型(类/特质)
所以在scala可以实现用val重写无参方法这种事情。
不过把字段、方法、单例 放在同一个命名空间还好理解,但“包”也与它们在同一个命名空间是怎么回事?
scala里包与字段和方法共享相同命名空间是为了让你引入包,而不仅仅是引入类型名以及单例对象的字段和方法。这点也与java不同,java只能import一个包下的类。
import java.{util => u}
class A {
val a = new u.ArrayList[String]();
def u = 2 //命名冲突
}
原则上,scala中的函数都可以省略空括号,然而在调用的方法超出其调用者对象的属性时,推荐仍保持空括号。
比如,方法执行了I/O, 或有改变可变状态,或读取了不是调用者字段的var,总之无论是直接还是非直接的使用可变对象
都应该加空括号
"hello".length // 没有副作用,可以省略括号
println() // 最好别省略()
上面是从有无副作用的情况下考虑的,另一种考虑方式是如果函数执行了逻辑操作就使用括号,如果仅是提供了对属性的访问则可以省略。
Pingback: Scala中的类和构造器 - 算法网
Pingback: Scala中的类和构造器 - 内存网