本節主要內容
- 單例對象
- 伴生對象與伴生類
- apply方法
- 應用程序對象
- 抽象類
單例對象
在某些應用場景下,我們可能不需要創建對象,而是想直接調用方法,但是Scala語言並不支持靜態成員,Scala通過單例對象來解決該問題。單例對象的創建方式如下:
object Student {
private var studentNo:Int=0;
def uniqueStudentNo()={
studentNo+=1
studentNo
}
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
object Student編碼後將生成兩個字節碼文件
利用javap命令查看字節碼文件內容有:
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Student$
警告: 二進制文件Student$包含cn.scala.xtwy.Student$
Compiled from "Student.scala"
public final class cn.scala.xtwy.Student$ {
public static final cn.scala.xtwy.Student$ MODULE$;
private int studentNo;
public static {};
private int studentNo();
private void studentNo_$eq(int);
public int uniqueStudentNo();
private cn.scala.xtwy.Student$();
}
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Student
警告: 二進制文件Student包含cn.scala.xtwy.Student
Compiled from "Student.scala"
public final class cn.scala.xtwy.Student {
public static void main(java.lang.String[]);
public static int uniqueStudentNo();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
不難看出,object Student最終生成了兩個類,分別是Student與Student,它們都是final類型的,而且Student的構造方法是私有的,通過靜態成員域 public
static final cn.scala.xtwy.Student$ MODULE$;
對Student$進行引用,這其實是Java語言中單例實現方式。
單例對象的使用方式同Java語言類引用靜態成員是一樣的。
伴生對象與伴生類
在前面單例對象的基礎之上,我們在object Student所在的文件內定義了一個class Student,此時object Student被稱爲class Student的伴生對象,而class Student被稱爲object Student的伴生類:
class Student(var name:String,age:Int)
object Student {
private var studentNo:Int=0;
def uniqueStudentNo()={
studentNo+=1
studentNo
}
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
}
}
//生成的字節碼文件如下:
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Student
警告: 二進制文件Student包含cn.scala.xtwy.Student
Compiled from "Student.scala"
public class cn.scala.xtwy.Student {
private java.lang.String name;
private int age;
public static void main(java.lang.String[]);
public static int uniqueStudentNo();
public java.lang.String name();
public void name_$eq(java.lang.String);
public int age();
public void age_$eq(int);
public cn.scala.xtwy.Student(java.lang.String, int);
}
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Student$
警告: 二進制文件Student$包含cn.scala.xtwy.Student$
Compiled from "Student.scala"
public final class cn.scala.xtwy.Student$ {
public static final cn.scala.xtwy.Student$ MODULE$;
private int studentNo;
public static {};
private int studentNo();
private void studentNo_$eq(int);
public int uniqueStudentNo();
public void main(java.lang.String[]);
private cn.scala.xtwy.Student$();
}
- 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
- 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
從上面的代碼中不難看出,其實伴生對象與伴生類本質上是不同的兩個類,只不過伴生類與伴生對象之間可以相互訪問到對主的成員包括私有的成員變量或方法,例如:
class Student(var name:String,var age:Int){
private var sex:Int=0
//直接訪問伴生對象的私有成員
def printCompanionObject()=println(Student.studentNo)
}
object Student {
private var studentNo:Int=0;
def uniqueStudentNo()={
studentNo+=1
studentNo
}
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
val s=new Student("john",29)
//直接訪問伴生類Student中的私有成員
println(s.sex)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
apply方法
在前幾節中我們提到,通過利用apply方法可以直接利用類名創建對象,例如前面在講集合的時候,可以通過val intList=List(1,2,3)這種方式創建初始化一個列表對象,其實它相當於調用val intList=List.apply(1,2,3),只不過val intList=List(1,2,3)這種創建方式更簡潔一點,但我們必須明確的是這種創建方式仍然避免不了new,它後面的實現機制仍然是new的方式,只不過我們自己在使用的時候可以省去new的操作。下面就讓我們來自己實現apply方法,代碼如下:
//定義Student類,該類稱爲伴生類,因爲在同一個源文件裏面,我們還定義了object Student
class Student(var name:String,var age:Int){
private var sex:Int=0
//直接訪問伴生對象的私有成員
def printCompanionObject()=println(Student.studentNo)
}
//伴生對象
object Student {
private var studentNo:Int=0;
def uniqueStudentNo()={
studentNo+=1
studentNo
}
//定義自己的apply方法
def apply(name:String,age:Int)=new Student(name,age)
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
val s=new Student("john",29)
//直接訪問伴生類Student中的私有成員
println(s.sex)
//直接利用類名進行對象的創建,這種方式實際上是調用前面的apply方法進行實現,這種方式的好處是避免了自己手動new去創建對象
val s1=Student("john",29)
println(s1.name)
println(s1.age)
}
}
- 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
- 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
應用程序對象
利用IDE開發scala應用程序時,在運行程序時必須指定main方法作爲程序的入口,例如:
object Student {
//必須定義mian方法作爲程序的入口才能執行
def main(args: Array[String]): Unit = {
val s1=Student("john",29)
println(s1.name)
println(s1.age)
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
除了這種方式之外,scala還提供了一種機制,即通過擴展App,在Scala IDE for Eclipse裏是通過new->scala app方式創建的
也可在代碼直接指定:
//擴展App後,程序可以直接運行,而不需要自己定義main方法,代碼更簡潔
object AppDemo extends App {
println("App Demo")
}
- 1
- 2
- 3
- 4
- 1
- 2
- 3
- 4
App其實是一種trait,它幫助我們定義了main方法。
抽象類
抽象類是一種不能被實例化的類,抽象類中包括了若干不能完整定義的方法,這些方法由子類去擴展定義自己的實現。
//scala中的抽象類定義
abstract class Animal {
def eat:Unit
}
//對應字節碼文件
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Animal.class
Compiled from "human.scala"
public abstract class cn.scala.xtwy.Animal {
public abstract void eat();
public cn.scala.xtwy.Animal();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
除抽象方法外,抽象類中還可以有抽象字段:
abstract class Animal {
//抽象字段(域)
//前面我們提到,一般類中定義字段的話必須初始化,而抽象類中則沒有這要求
var height:Int
//抽象方法
def eat:Unit
}
//Person繼承Animal,對eat方法進行了實現
//通過主構造器對height參數進行了初始化
class Person(var height:Int) extends Animal{
//對父類中的方法進行實現,注意這裏面可以不加override關鍵字
def eat()={
println("eat by mouth")
}
}
//通過擴展App創建程序的入口
object Person extends App{
new Person(10).eat()
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
//上面這幾個類會產生以下四個字節碼文件
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy 的目錄
2015/07/22 23:28 <DIR> .
2015/07/22 23:28 <DIR> ..
2015/07/22 23:28 675 Animal.class
2015/07/22 23:28 2,143 Person$.class
2015/07/22 23:28 699 Person$delayedInit$body.class
2015/07/22 23:28 1,741 Person.class
//字節碼內容如下:
//Animal類對應的字節碼,可以看到,字節碼中包括了抽象字段height的getter和setter方法,只不過它們都是抽象的
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Animal.class
Compiled from "Person.scala"
public abstract class cn.scala.xtwy.Animal {
public abstract int height();
public abstract void height_$eq(int);
public abstract void eat();
public cn.scala.xtwy.Animal();
}
//Person類對應的字節碼文件
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Person.class
Compiled from "Person.scala"
public class cn.scala.xtwy.Person extends cn.scala.xtwy.Animal {
private int height;
public static void main(java.lang.String[]);
public static void delayedInit(scala.Function0<scala.runtime.BoxedUnit>);
public static java.lang.String[] args();
public static void scala$App$_setter_$executionStart_$eq(long);
public static long executionStart();
public int height();
public void height_$eq(int);
public void eat();
public cn.scala.xtwy.Person(int);
}
//伴生對象Person對應的字節碼文件內容
D:\ScalaWorkspace\ScalaChapter06_2\bin\cn\scala\xtwy>javap -private Person$.clas
s
Compiled from "Person.scala"
public final class cn.scala.xtwy.Person$ implements scala.App {
public static final cn.scala.xtwy.Person$ MODULE$;
private final long executionStart;
private java.lang.String[] scala$App$$_args;
private final scala.collection.mutable.ListBuffer<scala.Function0<scala.runtim
e.BoxedUnit>> scala$App$$initCode;
public static {};
public long executionStart();
public java.lang.String[] scala$App$$_args();
public void scala$App$$_args_$eq(java.lang.String[]);
public scala.collection.mutable.ListBuffer<scala.Function0<scala.runtime.Boxed
Unit>> scala$App$$initCode();
public void scala$App$_setter_$executionStart_$eq(long);
public void scala$App$_setter_$scala$App$$initCode_$eq(scala.collection.mutabl
e.ListBuffer);
public java.lang.String[] args();
public void delayedInit(scala.Function0<scala.runtime.BoxedUnit>);
public void main(java.lang.String[]);
private cn.scala.xtwy.Person$();
}
- 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
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 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
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66