天天看點

scala 開發入門(5)-- 類與對象

類的定義

scala中的類與java語言中一樣都是用class定義

class Person{
//聲明一個變量,這裡成員變量必須初始化
var name:String = null //或者用占位符初始化 var name:String = _
}  //類的成員變量在聲明時必須初始化,除非是抽象類

//建立類對象
val p = new Person()
//直接修改成員變量name
p.name = "Jhon"
           

對象的定義

單例對象,使用時可以不建立對象而是直接用 類名.方法 來通路

object Student{
  private var studentNo:Int = 0
  def uniqueStudentNo() = {
    studentNo += 1
    studentNo}
}

//直接通過單例對象名稱通路其成員方法
Student.uniqueStudentNo()
res1:Int = 1
//單例對象中的成員變量狀态随程式執行而改變
Student.uniqueStudentNo()
res2:Int = 2
           

應用程式對象,定義一個main方法作為應用程式的入口

/**
  * 應用程式對象:通過定義main方法實作
  */
object Example{
  object Student{
   private var studentNo:Int = 0
   def uniqueStudentNo()={
     studentNo += 1
     studentNo}
     }
 //通過 main 方法作為程式的入口
def main(args:Array[String]){
  println(Student.uniqueStudentNo())
  }
}
           
/**
  *應用程式對象:通過混入 trait App 來實作
  */
object Example extends App {
  object Student {
     private var studentNo:Int = 0
     def uniqueStudentNo() = {
         studentNo += 1
         studentNo}
        }
     //直接寫可執行的代碼
  println(Student.uniqueStudentNo())
           

伴生類與伴生對象,将單例對象引申為類,差別其他類或對象非常重要的地方就是通路權限

/**
  *伴生對象與伴生類
  */
object Example extends App{
//伴生類 Student
  class Student{
    private var name:String = null}
//伴生對象
  object Student{
    private var studentNo:Int = 0
    def uniqueStudentNo() = {
        studentNo += 1
        studentNo}
       }
 }

//通路權限展示
object Example2 extends App{
 //伴生類Student
 class Student{
   private var name:String = null
   def getStudentNo = {
      Student.uniqueStudentNo()
      //伴生類Student 中可以直接通路伴生對象 Student 的私有成員
      Student.studentNo
      }
}
//伴生對象
object Student {
  private var studentNo:Int = 0
  def uniqueStudentNo() = {
      studentNo += 1
      studentNo}
  //直接通路伴生類對象的私有成員
  def printStudentName = println(new Student().name)
}
           

通過非顯式使用new關鍵字建立對象,在集合那部分已經大量使用,使用的就是伴生對象apply方法。如果希望在編寫代碼時,不通過 new Student() 這樣顯式的調用 new 關鍵字來建立對象,可以使用如下方式

/**
  *伴生對象與伴生類:不顯式的通過 new 關鍵字來建立對象
  */
object Example extends App{
 //伴生類Student
 class Student{
   var name:String = null
  }
 //伴生對象
 object Student{
   //apply方法,供非顯式 new 建立對象時調用
   def apply() = new Student()
   }

//無 new 方式建立對象,調用的是伴生對象的 apply 方法:def apply() = new Student()
val s = Student()
s.name = "John"
println(s.name)
}
           

主構造函數

//預設參數的主構造函數
class Person(var name:String = "",var age:Int = 18){
override def toString() = "name="+name",age="+age}

//不使用參數時,使用預設值
val p = new Person
p:Person = name=,age=18

//私有主構造函數,通過 private 關鍵字将主構造函數定義為私有
class Person private (var name:String,var age:Int)
val p = new Person("John",19)  //錯誤,外部不能調用私有主構造函數
           

輔助構造函數

同主構造函數一樣,輔助構造函數也有預設參數
/**
  *輔助構造函數
  */
object Example extends App{
  //定義無參的主構造函數
  class Person{
    //類成員
    private var name:String = null
    private var age:Int = 18
    private var sex:Int = 0

   //帶預設參數的輔助構造函數
   def this(name:String = "",age:Int = 18,sex:Int = 1){
      this()  //先調用主構造函數,否則會報錯
      this.name = name
      this.age = age
      this.sex = sex
      }
   override def toString = {
     val sexStr = if(sex==1) "男" else "女"
     s"name=$name,age=$age,sex=$sexStr"
      }
  }

println(new Person("John")) // name=John,age=18,sex=男
println(new Person)         // name=null,age=18,sex=女
}
從執行結果可以看出,第一個調用的是輔助構造函數,第二個調用的其實是無參的主構造函數
在建立對象時,編譯器會首先查找是否有主構造函數與待調用的構造函數比對,有則調用,沒有才會查找相應的輔助構造函數                從執行結果可以看出,第一個調用的是輔助構造函數,第二個調用的其實是無參的主構造函數
在建立對象時,編譯器會首先查找是否有主構造函數與待調用的構造函數比對,有則調用,沒有才會查找相應的輔助構造函數      

繼承與多态

//類的繼承
/**
  *類繼承
  */
object Example extends App{
  class Person(var name:String,var age:Int){
    override def toString:String = "name="+name+",age="+age
    }
  
  //通過extends 關鍵字實作類的繼承,注意 Student 中的name和age前面沒有 var 關鍵字修飾
  //表示這兩個成員繼承自 Person 類,var studentNo:String 則為 Student 類中定義的新成員
  class Student(name:String,age:Int,var studentNo:String) extends Person(name,age){
    override def toString:String = super.toString+",studentNo="+studentNo //方法重寫 }
  
  println(new Person("John",18))   //name=John,age=18/
  println(new Student("Nancy",19,"110831") //name=Nancy,age=19,studentNo=110831

多态就是可對父類方法進行重寫,未重寫則繼承父類方法
           

抽象類

抽象類是一種不能被執行個體化的類,抽象類中存在抽象成員變量或成員方法,這些成員方法或成員變量在子類中被具體化。

//普通類成員變量在定義時必須顯式初始化
class Person{
  var name:String = _
}

class Person{
  var name:String
}   //報錯

//成員變量如果不顯式初始化,則将類聲明為抽象類,通過 abstract 關鍵字來定義
abstract class Person{
 var name:String
}

//當子類繼承抽象類時,需在子類中對父類中的抽象成員變量進行初始化,否則子類也必須聲明為抽象類
//在子類中對父類中的抽象成員變量初始化,使用 override 關鍵字
class Student extends Person{
  override var name:String = _
 }
//override 也可以省略
class Student extends Person{
   var name:String = _
}
           
object Example extends App{
  abstract class Person{
  //抽象類中的具體成員變量
  var age:Int = 0
  //抽象類中的抽象成員變量
  var name:String
  //抽象類中的抽象方法
  def walk()
  //抽象類中的具體方法
  override def toString = name
}

 class Student extends Person{
  //對繼承自父類的抽象成員變量進行初始化,override 關鍵字可以省略
  override var name = _
  //對繼承自父類的抽象成員方法進行初始化,override 關鍵字可以省略
  override def walk():Unit = println("Walk like a Student")
 }

val p = new Student
p.walk()
}