2016-04-10-scala

单例对象

要点:
scala当中,不会像java那样提供static的关键字用于创建一个单例对象。但我们可以通过object这个关键字来定义一个单例对象,在object块里面的成员变量与方法都是静态的。但要注意的是:在java当中,static的静态成员变量、静态块是在类加载的时候就被执行了,而在scala当中,只有第一次调用的时候才会执行。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
object SingletonClass {

private var num = 0;

def getNum = {
num += 1;
num
}

}

object Main {

def main(args: Array[String]) {
println(SingletonClass.getNum)
println(SingletonClass.getNum)
}

}


out :
1
2

伴生对象

概念:
当一个类定义为class A,则对应的object A就是它的伴生对象。它能访问伴问伴生对象当中的任意成员变量,即使是private的也可以。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
//伴生对象
object SingletonClass {

private var num = 0;

def getNum = {
num += 1;
num
}

}

//伴生类
class SingletonClass {

private var id = SingletonClass.getNum;
private var num = 0;

def getNum(num : Int) = {
this.num += num
}

}

注意:
伴生对象通常用于作为伴生类的静态成员变量的封装区域。


apply方法讲解

object中:
当使用伴生对象来生成对象时,就会调用其apply方法
class中:
当直接使用new clazz的方式来创建对象的时候是不会调用类当中的apply方法的,只有当使用创建了的对象A,直接调用A()就能调用类当中的apply方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
class ArrApply{
def apply() = {
println("print from class")
//new ArrApply()
}

def doSomething() = {
println("doSomething")
}
}

object ArrApply{
def apply() = { //=号不能少,少了doSomethin方法调用的地方会报错,还没找到原因
println("print from object")
new ArrApply()
}
}

object ApplyOps {

def main(args: Array[String]) {
val arr = ArrApply() //通过伴生对象创建一个伴生类对象
arr.doSomething()

val array = new ArrApply()
array() //调用类的apply方法
}

}

scala继承

它的使用方法与java类似,只是在重写的时候要使用override关键字。但在java当中,是在子类的构造器中调用父类的构造器的,而scala中,是在定义子类的时候填满父类的主构造方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
class ExtendClass(name : String) {

val school = "GDUT"

def showInfo : String = {
school
}

def showName : String = { //当子类没有重写时,即使调用了changeName也返回构造值,因为这里返回的是父类的name,而修改的只是子类的name而已
name
}

override def toString = {
"in gdut"
}

}

class Student(var name : String) extends ExtendClass(name) {

override val school = "gdut"

override def showInfo : String = {
"a boy in " + school
}

def changeName(name : String) = {
this.name = name
}

override def showName : String = {
name
}

}

object ExtendOps {

def main(args: Array[String]) {

val student = new Student("xiaoming")
println(student.toString)
println(student.showInfo)
student.changeName("xiaodong")
println(student.showName)

}

}

抽象类

java类似,在scala当中也是通过abstract关键字来定义一个抽象类,对于抽象类当中的字段,如果没有赋值则是抽象的成员变量,对于方法如果没有具体的实现则为抽象方法。但要注意的是,在java当中抽象方法是要使用abstract来修饰的,但在scala当中,abstract只能用于修饰class。如果一个类不是抽象类,那么它的成员变量是一定要进行赋值的,可以是具体的值,也可以是一个占位符。而使用占位符只能是成员变量类型为var的情况。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
abstract class AbstractClass {

var name : String = "xiaoming"
var age : Int
def teach()

}

class MathTeacher extends AbstractClass {

override var age = 22

override def teach() = {
print("math teacher")
}

}

object AbstractOps {
def main(args: Array[String]) {
val teacher = new MathTeacher();
teacher.teach()
}
}

scala当中的接口-trait

scala当中的trait与java中的interface类似,但trait的功能更为强大,它能够有方法的具体实现(JDK1.8也可以通过default关键字来提供)。在使用triat的实现类的时候,我们还可以通过with关键字来给该对象混入其它的triat实现,这相当于一个动态的extends操作。在java当中多实现是用,来分割的,但scala当中是使用with

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
trait TriatClass {

def log()

}

trait OtherTriat {

def consoleLog(): Unit ={
println("console log...")
}

}

trait TriatClassImpl extends TriatClass{

override def log(): Unit ={
println("triatclassimpl...")
}

}

class ConcreteLog extends TriatClass {

override def log(): Unit ={
print("concretelog...")
}

}

object TriatOps {
def main(args: Array[String]) {
val log = new ConcreteLog
log.log()
val logger = new ConcreteLog with TriatClassImpl
logger.log()
val console = new ConcreteLog with OtherTriat //混入其它triat
console.log()
console.consoleLog()
}

}