本节主要内容
- 单例对象
- 伴生对象与伴生类
- apply方法
- 应用程序对象
- 抽象类
单例对象
在某些应用场景下,我们可能不需要创建对象,而是想直接调用方法,但是Scala语言并不支持静态成员,Scala通过单例对象来解决该问题。单例对象的创建方式如下:
object Student {
private var studentNo:Int=0;
def uniqueStudentNo()={
studentNo+=1
studentNo
}
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
}
}
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)
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方法,代码如下:
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 apply(name:String,age:Int)=new Student(name,age)
def main(args: Array[String]): Unit = {
println(Student.uniqueStudentNo())
val s=new Student("john",29)
println(s.sex)
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)
}
}
除了这种方式之外,scala还提供了一种机制,即通过扩展App,在Scala IDE for Eclipse里是通过new->scala app方式创建的
也可在代码直接指定:
object AppDemo extends App {
println("App Demo")
}
App其实是一种trait,它帮助我们定义了main方法。
抽象类
抽象类是一种不能被实例化的类,抽象类中包括了若干不能完整定义的方法,这些方法由子类去扩展定义自己的实现。
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();
}
除抽象方法外,抽象类中还可以有抽象字段:
abstract class Animal {
var height:Int
def eat:Unit
}
class Person(var height:Int) extends Animal{
def eat()={
println("eat by mouth")
}
}
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
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();
}
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);
}
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