Scala支持面向对象编程, 其面向对象特性与Java有共同之处并添加了很多新的特性。
类定义
scala使用class
关键字定义类:
class MyComplex(real0:Double, image0:Double) {
var real:Double = real0;
var image:Double = image0;
private val eps:Double = 0.001;
def show() {
println("%f+%fi".format(this.real, this.image));
}
}
scala> var c = new MyComplex(1,1);
c: MyComplex = MyComplex@49c17ba4
scala> c.show()
1.000000+1.000000i
定义的语法与Java类似,同样采用this
关键字访问实例自身。并且采用和Java类似的三种访问修饰符:
private
: 仅类自身的方法可以访问protected
: 仅类自身和派生类的方法可以访问public
: 所有方法都可以访问, 默认访问权限
scala类定义语法与Java最大的不同在于,类声明中含有参数声明。scala的整个类声明体即为一个函数体,我们称其为类的主构造函数。
在类实例化时类声明中所有代码都将被执行,属性和方法的声明语句将定义相应的类成员。也因为如此, 所有属性声明时必须给出默认值.
给出MyComplex
类声明的Java版本, 可以让我们直观的认识主构造函数:
class MyComplex {
public Double real;
public Double image;
public MyComplex(Double real0, Double image0) {
this.real = real0;
this.image = image0;
}
public void show() {
println("%f+%fi".format(this.real, this.image));
}
}
辅助构造函数
scala支持重载方法, 重载构造函数需要使用this
关键字重载, 它们被称为辅助构造函数:
class MyComplex(real0:Double, image0:Double) {
var real:Double = real0;
var image:Double = image0;
val eps:Double = 0.001;
def this(real0:Int, image0:Int) {
this(real0.toDouble, image0.toDouble);
}
def show() {
println("%f+%fi".format(this.real, this.image));
}
}
调用辅助构造函数时,必须先调用主构造函数或其它已经定义好的构造函数
object
class
关键字定义的类可以多次初始化, 而object
关键字定义的是一个单例类,声明完成后即可访问,不需要再进行实例化:
object Config {
var username:String = "";
var password:String = "";
var mode:Int = 0;
def show() {
println("username:" + this.username);
println("password" + this.password);
println("mode" + this.mode);
}
}
scala> Config.username
res: String = ""
scala> Config.show()
username:
password
mode0
伴生对象
在面向对象的设计模式中静态属性和方法被认为是一种不好的实践, 应该采用单例模式代替.
伴生对象与类同名, 类对象和伴生对象可以互相访问对方的private成员, 编译后出现在同一个.class
文件中.
class User {
var username:String = "";
var password:String = "";
var mode:Int = 0;
User.add();
println(User.count);
}
object User {
private var count:Int = 0;
private def add() {
this.count += 1;
}
def main(args: Array[String]) {
var u = new User();
println(this.count);
}
}
编译执行:
$ scalac companion.scala
cat: /release: No such file or directory
$ ls
User$.class User.class companion.scala
$ scala User
cat: /release: No such file or directory
1
1
继承
scala同样采用extends
关键字进行继承:
class MyComplex(real0:Double, image0:Double) {
var real:Double = real0;
var image:Double = image0;
val eps:Double = 0.001;
def this(real0:Int, image0:Int) {
this(real0.toDouble, image0.toDouble);
}
def show() {
println("%f+%fi".format(this.real, this.image));
}
}
class MyComplex2(real0:Double, image0:Double)
extends MyComplex(real0, image0) {
override val eps:Double = 0.001;
override def show() {
if (this.real != 0) {
println("%f+%fi".format(this.real, this.image));
}
else {
println("%fi".format(this.image));
}
}
}
在继承声明中需要向基类构造函数传递实参.
覆盖基类的非抽象属性和非抽象方法时必须使用override
关键字.
抽象类
使用abstract
关键字可以定义抽象类:
abstract class AbstractComplex {
var real:Double;
var image:Double;
val eps:Double = 0.001;
def show;
}
抽象类允许不初始化属性或不实现方法,派生类在重写抽象属性和方法时不需要override关键字:
class MyComplex(real0:Double, image0:Double) extends AbstractComplex {
var real:Double = real0;
var image:Double = image0;
def show() {
println("%f+%fi".format(this.real, this.image));
}
}
继承了抽象类的类必须实现所有属性和方法, 否则需要使用abstract
关键字声明派生类仍然是抽象类:
abstract class MyComplex(real0:Double, image0:Double) extends AbstractComplex {
var real:Double = real0;
var image:Double = image0;
}
trait
trait类似于Java中的interface, 用于定义类的接口. 与Java类似, scala只允许继承一个实体或抽象类但允许实现多个trait
.
不同的是trait可以定义属性和方法, 并根据已有属性和方法生成新的属性和方法.
trait ComplexTrait {
def equalWith(x:ComplexTrait): Boolean;
def notEqualWith()(x:ComplexTrait): Boolean = !equalWith(x);
}
scala使用extends
关键字来继承trait, 若已经使用了extends则需使用with
关键字对trait进行多继承:
// class MyComplex(real0:Double, image0:Double)
// extends ComplexTrait {...}
class MyComplex(real0:Double, image0:Double)
extends AbstractComplex with ComplexTrait {
var real:Double = real0;
var image:Double = image0;
def equalWith(x:ComplexTrait):Boolean = {
if (this.real == x.real && this.image == x.image) {
return true;
}
else {
return false;
}
}
def show() {
println("%f+%fi".format(this.real, this.image));
}
}
继承trait的类必须实现trait所有未实现的属性和方法.