/ 城寒 / Scala - Class & Object

Scala - Class & Object

2018-01-27 posted in [Scala]

参考

类和对象

类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。类是用于创建对象的蓝图,它是一个定义包括在特定类型的对象中的方法和变量的软件模板。 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是一个纯粹的面向对象语言,不允许有任何破坏对象模型的机制存在,比如类的静态变量、函数等。