Scala讲座:类定义和构造函数

开发 后端
本文选自Scala讲座的第三篇的第一部分,首先,从定义Java中的类出发,然后看看如何定义Scala中的类及构造函数,希望大家喜欢。

本文节选自最近在日本十分流行的Scala讲座系列的第三篇,由JavaEye的fineqtbull翻译。本系列的作者牛尾刚在日本写过不少有关Java和Ruby的书籍,相当受欢迎。

序言

到这为止牛尾先生作了一下Scala语言的介绍,接下来以微型旅游的形式做一下有关Scala语法特点的探险。如果是初次接触的读者可以大略的读一下第一和第二回的讲座,就可以顺畅地读懂本文了。

这次旅行准备访问的是,类定义和构造函数;混合Scala与Java程序以及与Java语言在语法上的差别;称为特征(Trait)的mixin型多重继承;函数定义和函数式编程;类型层次和集合;模式匹配;XML文本操作;等主题。

首先,作为复习我们先整理一下Scala语言的要点。

• 事实1:Scala中可以简单使用所有Java类,Java中也可以自由调用Scala类。Scala类还可以定义为Java类的子类。也就是说,庞大的已有Java、J2EE、Java ME和CLDC资源可以被更有效和合理地应用了。(在Net上,虽然现在的版本还不支持,1.x版曾经支持过,将来也有复活的计划)

• 事实2:Scala在JVM上被执行,编译后的代码执行性能基本与Java代码不相上下。结果是比大多数脚本语言的速度都快一位数以上。

• 事实3:Scala一方面是纯面向对象的语言,另一方面在这框架中提供了完全的函数式编程的功能。Scala的所有数据都是对象,函数也是对象,可以作为数据来操作。

• 事实4:Scala在对于开发Javac和Java Generics有贡献的Martin Ordersky教授所率领的强大的开放体制下被开发,不是实验室的实验品,而是将来可以期待的通用编程语言。Scala发布的频率非常快,文档也很丰富,现在的版本是Scala2.7.1 final(2008/8)。

类定义和构造函数

那么,定义一下类吧。首先定义一下在语言介绍中一直用到的Person类。首先是Java类

  1. public class Person  
  2. {  
  3. private String lastName; //姓  
  4. private String firstName; //名  
  5. private Person spouse; //配偶的Person对象  
  6. public Person(String fn, String ln, Person s)  
  7. {  
  8. lastName = ln; firstName = fn; spouse = s;  
  9. }  
  10. public Person(String fn, String ln)  
  11. {  
  12. this(fn, ln, null); //未婚时没有配偶  
  13. }  
  14. public String getFirstName()  
  15. {  
  16. return firstName;  
  17. }  
  18. public String getLastName()  
  19. {  
  20. return lastName;  
  21. }  
  22. public Person getSpouse()  
  23. {  
  24. return spouse;  
  25. }  
  26. public void setSpouse(Person p)  
  27. {  
  28. spouse = p;  
  29. //没有考虑婚姻对姓和名的影响  
  30. }  
  31. public String introduction()  
  32. {  
  33. return "我的名字是," + firstName + " " + lastName +  
  34. (spouse != null ?  
  35. " 对方的名字是," + spouse.firstName + " " + spouse.lastName + " 。" :  
  36. " 。");  
  37. }  
  38. }  

下面是用Scala写的同样内容

  1. class Person(fn : String, ln : String, s : Person)  
  2. {  
  3. val lastName = ln; //没有private修饰符则认为是public  
  4. val firstName = fn; //从构造函数的参数类型推断为String  
  5. var spouse = s; //从构造函数的参数类型推断为Person  
  6. def this(fn : String, ln : String) = { this(fn, ln, null); }  
  7. def introduction() : String =  
  8. return "我的名字是, " + lastName + " " + firstName +  
  9. (if (spouse != null" 对方的名字是, " + spouse.lastName + " " + spouse.firstName + "。" else "。");  
  10. }  

从行数来看大概缩短为1/3,代码变得非常简洁了。用val来定义常量,var来定义可再赋值的实例属性。用def来定义方法。Scala的目的之一就是使书写的代码更简洁易读。

在Scala中实例属性默认为public,可以用该实例属性名来直接存取属性的值。

  1. scala> val p0 = new Person("Fei""Zhang")  
  2. p0: Person = Person@6e9b6a 
  3. scala> p0.introduction  
  4. res1: String = 我的名字是, Zhang Fei。  

而且Scala对于调用方法的“.”符号,在不发生歧义的情况下可以替换为空格。但是,这里不能加上空的参数表()。

  1. scala> p0 firstName //同p0.firstName等同  
  2. res3: String = Fei  
  3. scala> p0 spouse //现在未婚,所以spouse的值为null  
  4. res4: Person = null 
  5. scala> p0.spouse() //注意,Scala中.m和.m()的含义不同  
  6. :6: error: p0.spouse of type Person does not take parameters  
  7. p0.spouse() 

接下来那让ZhangFei结婚吧。先准备好女方DiaoChan对象,然后把她设置到p0的spouse属性。这时构造函数第三个参数为配偶,所以赋予p0。

为了防止误解先说明一下,p0最初是用val来定义的所以是不可再赋值的,不过改变p0所指对象的内部状态还是可以的。因此,如下所示结婚后还可以让他再婚。

  1. scala> p0 spouse = new Person("Chan""Diao", p0) //DiaoChan和ZhangFei结婚  
  2. scala> (p0 spouse) firstName //写成p0 spouse firstName就会出错  
  3. res6: String = Chan  
  4. scala> p0 spouse = null //ZhangFei离婚  
  5. scala> p0 spouse = new Person("Shi""Xi", p0) //和XiShi再婚  

定义Scala的类比较有趣的是定义基本(primary)构造函数时在类名称后直接加上构造函数的参数表。基本构造函数参数的类型不可省略(包括模式匹配,这是对象的类型信息的基础,不能省略也是当然的)。另一方面,可以注意到类型定义中的变量定义没有指定类型,这都是靠从构造函数参数的类型推断出来的。

而且声明为def this(ln:String, fn:String)的派生构造函数也是从基本构造函数而来的。函数体内通过调用this(ln, fn, null),给基本构造函数的第三个参数赋予null来实现为了未婚人士准备的只有两个参数的构造函数。

这个类定义还可以缩短如下

  1. class Person(val firstName:String, val lastName:String, var spouse:Person) {  
  2. def this(fn:String, ln:String) = this(fn, ln, null)  
  3. def introduction = "我的名字是," + lastName + " " + firstName +  
  4. (if (spouse != null",对方的名字是," + spouse.lastName + " " + spouse.firstName + "。" else "。")  
  5. }  

由于在类中基本构造函数的参数定义前加上val或var后,对应的实例属性就会被定义,所以原来的属性定义就不需要了。而且,编译器会自动追加用于存取这些属性的方法。Scala中基本上可以去除语句尾部的“;”符号,这里也都去除了。

  1. scala> val p1 = new Person("Yu""Guan"new Person("ZheTian""Wu"))  
  2. p1: Person = Person@904f75 
  3. scala> p1.lastName  
  4. res7: String = Guan  
  5. scala> p1.spouse  
  6. res8: Person = Person@2e879 

上述程序中描述对象的字符串比较难解,下面就扩展一下类使他显示姓和名吧。任何对象的文字描述是由对象的最根类Any的toString:String方法来实现的。在各个类中使用自己的实现来覆盖这个方法就可以了,这里的显示格式为[姓:firstName 名:lastName 配偶:没有或(姓:firstName 名:lastName)]。另外,Scala中覆盖父类的方法一定要加上override修饰符。

  1. class Person ... { ...  
  2. override def toString : String = super.toString + " [姓: " + lastName + " 名: " + firstName + " 配偶: " + (if (spouse != null" ("+ spouse.lastName + "," + spouse.firstName + ")" else "没有") + "]" 
  3. ...} 

下面是修改后的效果

  1. scala> val p1 = new Person("Yu""Guan"new Person("ZheTian""Wu"))  
  2. p1: Person = Person@4a0ac5 [姓: Guan 名: Yu 配偶: (Wu, ZheTian)]  
  3. scala> p1  
  4. res0: Person = Person@4a0ac5 [姓: Guan 名: Yu 配偶: (Wu, ZheTian)] 

Scala讲座中类定义和构造函数的内容就到这里。

【编辑推荐】

  1. Scala讲座:面向对象和函数式的特点总结
  2. Scala讲座:函数式编程处理树结构数据
  3. Scala讲座:编程的思考方法
  4. Scala讲座:将函数作为第一类对象来处理
  5. Scala讲座:全局变量问题的解决
责任编辑:book05 来源: JavaEye博客
相关推荐

2009-12-11 10:44:00

Scala讲座函数 scala

2009-09-27 15:29:00

Scala讲座面向对象Scala

2009-09-24 09:38:00

Scala讲座第一类对象scala

2009-12-11 10:45:00

Scala讲座类型系统功能

2009-09-27 15:23:00

Scala讲座函数式编程Scala

2009-07-20 16:56:51

Scala类的定义

2009-12-11 10:43:00

Scala讲座混入多重继承类型层次

2009-09-24 09:41:00

Scala讲座Scala

2009-12-11 10:43:00

Scala讲座操作符函数

2009-07-21 17:21:57

Scala定义函数

2010-01-28 10:49:22

C++构造函数

2009-07-22 08:45:35

Scala超类构造器override修饰符

2009-09-24 09:28:00

Scala讲座全局变量scala

2010-01-27 10:13:22

C++类对象

2010-01-25 14:00:27

C++类

2009-12-10 13:37:16

PHP parent

2009-06-16 17:54:38

Scala类语法语义

2009-07-08 16:52:29

ScalaScala教程

2009-09-09 11:37:08

Scala的模式匹配

2009-07-21 17:29:25

Scala第一类函数
点赞
收藏

51CTO技术栈公众号