Scala - Class & Object
类和对象
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。 Scala中的类不声明为public,一个Scala源文件中可以有多个类。继承一个基类跟Java很相似, 但我们需要注意以下几点:
重写一个非抽象方法必须使用override修饰符。 只有主构造函数才可以往基类的构造函数里写参数。 在子类中重写超类(父类)的抽象方法时,你不需要使用override关键字。
//类默认是public级别的
//主构造器在类名后,参数会被声明字段,若参数没有使用var或者val声明,则会被声明称私有字段
//实例化类的时候,类中的语句会被执行:println("person")
class Person(name:String,var age:Int) {
println("person")
def show(): Unit = {
println("show.."+name)
}
var gender:String=_
//次构造器必须调用主构造器,参数不能使用var
def this(name:String,age:Int, gender:String){
this(name,age)
this.gender=gender
}
}
class Person{
var age=18 //字段必须得初始化()
def Age=age //这个是方法,没有参数可以省略()
def incremen(){this.age+=1}
}
class Student{
var age=20 //底层编译器会自动为私有的age添加get和set的公有方法,可以理解为伪public类型
private[this] var gender="male" //private[this] 只有该类的this可以使用
private var name="clow" //声明了private,底层编译器会自动为私有的name添加get和set的私有方法
//但是可以自己定义属性方法
def getName=this.name
def setName(value:String){this.name=value}
}
//构造器的使用
class Teacher {
var age: Int = _
var name: String = _ //可以预留
//重载的构造器和C#里面的public Teacher(){}类似
def this(age: Int, name: String){
this() //必须得调用一次主构造器
this.age=age
this.name=name
}
}
import java.io._
class Point(val xc: Int, val yc: Int) {
var x: Int = xc
var y: Int = yc
def move(dx: Int, dy: Int) {
x = x + dx
y = y + dy
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
}
}
class Location(override val xc: Int, override val yc: Int,
val zc :Int) extends Point(xc, yc){
var z: Int = zc
def move(dx: Int, dy: Int, dz: Int) {
x = x + dx
y = y + dy
z = z + dz
println ("x 的坐标点 : " + x);
println ("y 的坐标点 : " + y);
println ("z 的坐标点 : " + z);
}
}
object Test {
def main(args: Array[String]) {
val loc = new Location(10, 20, 15);
// 移到一个新的位置
loc.move(10, 10, 5);
}
}
Scala重写一个非抽象方法,必须用override修饰符。
class Person {
var name = ""
override def toString = getClass.getName + "[name=" + name + "]"
}
class Employee extends Person {
var salary = 0.0
override def toString = super.toString + "[salary=" + salary + "]"
}
object Test extends App {
val fred = new Employee
fred.name = "Fred"
fred.salary = 50000
println(fred)
}
Scala 单例对象
在 Scala 中,是没有 static 这个东西的,但是它也为我们提供了单例模式的实现方法,那就是使用关键字 object。 Scala 中使用单例模式时,除了定义的类之外,还要定义一个同名的 object 对象,它和类的区别是,object对象不能带参数。因为你不能用new关键字实例化一个单例对象,你没机会传递给它参数。每个单例对象都被作为由一个静态变量指向的虚构类:synthetic class的一个实例来实现,因此它们与Java静态类有着相同的初始化语法。Scala程序特别要指出的是,单例对象会在第一次被访问的时候初始化。 不与伴生类共享名称的单例对象被称为孤立对象:standalone object。最常见的就是程序入口:
object AbstractTypeTest1 extends Application {
def newIntSeqBuf(elem1: Int, elem2: Int): IntSeqBuffer =
new IntSeqBuffer {
type T = List[U]
val element = List(elem1, elem2)
}
val buf = newIntSeqBuf(7, 8)
println("length = " + buf.length)
println("content = " + buf.element)
}
当单例对象与某个类共享同一个名称时,他被称作是这个类的伴生对象:companion object。你必须在同一个源文件里定义类和它的伴生对象。类被称为是这个单例对象的伴生类:companion class。类和它的伴生对象可以互相访问其私有成员。 一个伴生对象的示例:
import scala.collection.mutable.Map
class ChecksumAccumulator {
private var sum = 0
def add(b: Byte) {
sum += b
}
def checksum(): Int = ~(sum & 0xFF) + 1
}
object ChecksumAccumulator {
private val cache = Map[String, Int]()
def calculate(s: String): Int =
if (cache.contains(s))
cache(s)
else {
val acc = new ChecksumAccumulator
for (c <- s) acc.add(c.toByte)
val cs = acc.checksum()
cache += (s -> cs)
cs
}
}
object Summer {
def main(args: Array[String]) {
println(ChecksumAccumulator.calculate("Every value is an object."))
}
}
单例模式就控制类实例的个数,通过伴生对象来访问类的实例就提供了控制实例个数的机会。一个简单示例:
class Worker private{
def work() = println("I am the only worker!")
}
object Worker{
val worker = new Worker
def GetWorkInstance() : Worker = {
worker.work()
worker
}
}
object Job{
def main(args: Array[String]) {
for (i <- 1 to 5) {
Worker.GetWorkInstance();
}
}
}
// 结果
// I am the only worker!
// Worker@57fa26b7
// I am the only worker!
// Worker@57fa26b7
// I am the only worker!
// Worker@57fa26b7
// I am the only worker!
// Worker@57fa26b7
// I am the only worker!
// Worker@57fa26b7
class Worker private声明了Worker的首构造函数是私有的,这样Worker的所有构造函数都不能直接被外部调用,因为所有从构造函数都会首先调用其他构造函数(可以是主构造函数,也可以是从构造函数),结果就是主构造函数是类的唯一入口点。 另一方面,Worker.GetWorkInstance();有点类似静态函数调用,但在Scala中这是不对的。Scala会隐式地调用apply来创建一个伴生对象的实例。Scala是一个纯粹的面向对象语言,不允许有任何破坏对象模型的机制存在,比如类的静态变量、函数等。