Scala的强大之一在于它支持函数式编程,之二在于它可以Java无缝整合。所以Scala也是一门OO语言,类作为面向对象的基础概念,在Scala中也是必不可少的。
Scala类的定义与Java虽出同门,但有所区别,下面就探索一下Scala的类。
类作为对象的蓝图,在使用前要进行定义
class Test {}
这是一个没有方法,没有属性,没有构造参数的简单类,有了它,就可以创建对象
val test = new Test
对象通常由两部分组成:属性和方法,属性代表状态,方法代表行为。方法的定义及使用在前面以及介绍,下面具体讨论scala类中的属性。
如果熟悉Java 就会知道,JavaBean规范规定:私有属性 + getter/setter方法构成一个标准的JavaBean。在Java中构造JavaBean对象是一件很麻烦的事情
public class JvaBean1 {
private String name;
private String age;
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setAge(String age) {
this.age = age;
}
public String getAge{
return age;
}
}
然后,Scala为了保持简洁 提高开发效率,确是为程序员做了很多工作,先看一个例子
class Test {
var name = ""
var age = ""
}
*由于val变量不可改变,此处用var定义来说明问题
对于Test的两个属性,用如下方式操作
object Test {
def main(args: Array[String]) {
val test = new Test
test.name = "zhangsan"
test.age = "lisi"
println(test.name)
println(test.age)
}
}
来看一些Test类对应的Java源码,会发现很多有意思的事
public class Test
{
private String name = "";
private String age = "";
public static void main(String[] paramArrayOfString)
{
Test..MODULE$.main(paramArrayOfString);
}
public String name()
{
return this.name; }
public void name_$eq(String x$1) { this.name = x$1; }
public String age() { return this.age; }
public void age_$eq(String x$1) { this.age = x$1;
}
}
正如所看到的,name
和age
被翻译成了标准的Javabean形式-私有属性+setter/getter,那么,很多人会有疑问了, 为什么 getter和setter方法的调用方式相同呢?
实际上, test.name = "张三"
中的 name =
对应于 name_$eq
,"zhangsan"
是传入的值, 而println(test.name)
中的test.name
对应name()
方法,
对于val变量,scala会翻译成私有字段 + getter/setter
那么,对于val变量呢,下面来看一下
class Test{
val name = ""
}
public class Test
{
private final String name = "";
public String name() {
return this.name;
}
}
看到了吧,private final + getter
private final + getter
,只能获取,不能修改如果用private修饰变量会怎么样?
class Test{
private var name = ""
}
java代码如下
public class Test
{
private String name = "";
private String name() {
return this.name;
}
private void name_$eq(String x$1) {
this.name = x$1;
}
}
私有字段 + 私有 getter/setter
scala中还有一种更加严重的访问控制,private[this]
,它可以吧属性完全限制在当前对象内
class Test{
private[this] var name = ""
}
public class Test
{
private String name = "";
}
private[this]
修饰的属性不会生成getter/setter方法到此为止,已经看到了scala处理类的属性的大致思路,但同时,也会产出更大的疑惑,scala的getter/setter并不符合JavaBean规范,这样一来,scala与Java无缝兼容不久是做梦吗?因为很多工具类库都依赖于标准的JavaBean。
如果连这种简单粗暴的问题都没有解决方案,那scala还是去屎吧。看下面的例子
import scala.beans.BeanProperty
class Test{
@BeanProperty
var name = "zhangsan"
}
public class Test
{
private String name = "zhangsan";
public String name() { return this.name; }
public void name_$eq(String x$1) { this.name = x$1; }
public void setName(String x$1) { this.name = x$1; }
public String getName() { return name();
}
}
为属性添加@BeanProperty
注解后,scala除了会生成scala规范的getter/setter,同时也生成了符合JavaBean规范的getter/setter
,完美解决。
总结一下:
1.val name 生成getter
2.var name 生成getter + setter
3.private var/val name 生成私有的 getter/setter
4.private [this] val/var name 不生成getter/setter
5.@BeanProperty val/var name 同时生成符合scala和Java规范的
getter/setter
下面来讨论一下类是另一个组成部分:构造器。
还是先从一个简单的例子开始
class Test(name: String) { println(name) def this(name: String, age: String) { this(name) println(age) } }
然后再看一下这个简单类的Java代码
public class Test
{
public Test(String name)
{
Predef..MODULE$.println(name);
}
public Test(String name, String age) {
this(name);
Predef..MODULE$.println(age);
}
}
很简单,scala构建了一个带有一个参数的构造器,并将println脚本添到了构造器中。
从上面的简单示例中可以看到,scala的构造器定义与类定义交织在一起,即在类名后直接构建构造器参数,开始可能会感觉别扭,但会越来越发现这确实是一个即简洁又高效的做法。
上面的例子中主要包含了两部分内容:主构造器和辅助构造器
主构造器是类名后面的部分,在主构造器中可以声明任意类型的参数或 var/val。
class Test(@BeanProperty var name: String = "zhangsan") {
}
class Test(name:String) { }
辅助构造器类似于Java中的构造器重载,可以使类支持多种形式的构造。辅助构造器必须直接或间接的以调用主构造器开始
class Test(name: String) { println(name) def this(name: String, age: String) { this(name) println(age) } def this(name: String, age: String, location: String){ this(name, age) println(location) } }