许昌城乡建设局网站,注册公司条件和要求,如何快捷建企业网站,虚拟主机推荐3.Scala面向对象编程
3.1类和对象
3.1.1类
类是用class开头的代码定义#xff0c;定义完成后可以用new类名的方式构造一个对象#xff0c;对象的类型是这个类。类中定义的var和val类型变量称为字段#xff0c;用def定义的函数称为方法。字段也称为实例变量#xff0c;因…3.Scala面向对象编程
3.1类和对象
3.1.1类
类是用class开头的代码定义定义完成后可以用new类名的方式构造一个对象对象的类型是这个类。类中定义的var和val类型变量称为字段用def定义的函数称为方法。字段也称为实例变量因为每个被构造出来的对象都有自己的字段但所有的对象公用同样的方法。也就是说定义一个类之后每个对象的变量存储在独立的空间互不相同每个对象的方法是一样的存储在同样的空间。使用new创建的对象可以赋值给一个变量赋值给用val定义的变量则这个变量之后不得被赋值给新的对象。代码如下
scala class Students {| var name None| def register(n:String) name n| }
// defined class Students
scala val stu new Students
val stu: Students Students4fc454d5
scala stu.name
val res29: String None
scala stu.register(Bob)
scala stu.name
val res30: String Bob
scala stu.register(Jia)
scala stu.name
val res31: String Jia
scala stu new Students
-- [E052] Type Error: --------------------------------------------------------------------------------------------------
1 |stu new Students|^^^^^^^^^^^^^^^^^^|Reassignment to val stu|| longer explanation available when compiling with -explain
1 error found
类的成员都是公共的在 外部都可以被访问。如果不想被其他对象访问可以在变量前加上private关键字。
3.1.2类的构造方法
主构造方法
Scala不同于CPython等语言Scala没有专门的主构造语法在类名后可以定义若干参数列表用于传递参数参数会在初始化对象是传给类中的变量。类内部非字段非方法的代码都被当做“主构造方法”。
scala class Students(n:String) {| val name n| println(A student named n has been registered.)| }
// defined class Students
scala val stu new Students(Tom)
A student namedTom has been registered.
val stu: Students Students33004de5
这里println既不是字段也不是方法所以被当成主构造函数的一部分。
辅助构造方法
在类的内部使用 def this(...)定义一个辅助构造方法其第一步的行为必须是调用该类的另一个构造方法即第一句必须是this(...)要么是主构造方法要么是之前的另一个辅助构造方法。这种规则让任何构造方法最终都会调用类的主构造方法使得主构造方法成为类的单一入口。
scala class Students(n:String) {| val name n| def this() this(None)| println(A student named n has been registered.)| }
// defined class Students
scala val stu new Students
A student named None has been registered.
val stu: Students Students6f319f62
scala val stu2c new Students(Jia)
A student named Jia has been registered.
val stu2c: Students Students5a2e250b
这时存在两个构造函数主构造函数需要传入一个String类型的量用于初始化辅助析构函数不需要传入因为它已经把这个量定义为了None。去掉这个析构函数新创建对象时不传入String会导致报错
scala class Students(n:String) {| val name n| println(A student named n has been registered.)| }
// defined class Students
scala val stu new Students
-- [E171] Type Error: --------------------------------------------------------------------------------------------------
1 |val stu new Students| ^^^^^^^^^^^^| missing argument for parameter n of constructor Students in class Students: (n: String): Students
1 error found
不能定义两个有歧义的辅助构造函数这样写编译器无法确认在无参构造时究竟该调用哪一个构造函数
scala class Students(n:String) {| val name n| def this() this(None)| def this() this(Jia)| println(A student named n has been registered.)| }
-- [E120] Naming Error: ------------------------------------------------------------------------------------------------
4 |def this() this(Jia)| ^| Double definition:| def init(): Students in class Students at line 3 and| def init(): Students in class Students at line 4| have the same type after erasure.|| Consider adding a targetName annotation to one of the conflicting definitions| for disambiguation.
1 error found
析构函数
Scala不需要定义析构函数。
私有主构造方法
在类的定义时加入private关键字则主构造函数是私有的外部无法调用主构造函数创建对象只能使用其他公有的辅助构造方法或者工厂方法专门用于构造对象的方法
scala class Students private (n:String,m:Int) {| val name n| val score m| def this(n:String) this(n,100)| println(n s score is m)| }
// defined class Students
scala val stu new Students(Bill,90)
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |val stu new Students(Bill,90)| ^^^^^^^^^| Found: (String, Int)| Required: String|| longer explanation available when compiling with -explain
1 error found
scala val stu new Students(Bill)
Bills score is 100
val stu: Students Students45f675a4
主构造方法需要传入两个参数但它是用private修饰的所以外部无法调用。定义的辅助析构函数指定了第二个参数是100只需要传入一个参数因此外部可以调用这个辅助析构方法。
3.1.3重写toString方法
在构造一个Students类的对象时Scala解释器打印了一串信息Students45f675a4这其实来自Students类的toString方法这个方法返回一个字符串构造完一个对象时被自动调用这个方法是由所有Scala类隐式继承而来的默认的toString方法将会简单地打印类名一个“”符号和一个十六进制数。如果向打印更多有用信息可以自定义toString方法但需要加上override关键字。
scala class Students(n:String) {| val name n| override def toString A student named n .| }
// defined class Students
scala val stu new Students(Jia)
val stu: Students A student named Jia.
3.1.4方法重载
与C类似Scala支持方法重载即在类内可以定义多个同名的方法但参数主要是参数类型不一样这个方法有很多不同版本这称为方法重载。函数真正的特征是它的参数而非函数名或返回类型。它与重写定义不同重写是子类覆盖了超类的某个方法。
3.1.5类参数
Scala允许在类参数前加上val或var来修饰这样可以在类的内部生成一个与参数同名的公有字段。还可以使用private、protected、override来表面字段的权限。如果参数没有任何关键字那么它就仅仅是参数不是类的成员只能用初始化字段赋值内部无法修改外部无法访问。如前文中的参数加上val也算加上了关键字可以从外部访问内部可以修改
scala class Students(val name: String, var score: Int) {| def exam(s:Int) score s| override def toString name s score is score .| }
// defined class Students
scala val stu new Students(Tim,90)
val stu: Students Tims score is 90.
scala stu.exam(100)
scala stu.score
val res32: Int 100
3.1.6单例对象与伴生对象
除了使用new创建一个对象也可以使用object但它没有参数和构造方法且数量只能有一个因此被称为单例对象。如果某个单例对象和某个类同名则称单例对象是这个类的伴生对象这个类称为这个单例对象的伴生类。伴生类和伴生对象必须在同一个文件中并且可以互相访问对方的所有成员。单例对象和类一样也可以定义字段和方法也可以包含别的类和单例对象的定义。单例对象也可以用于大宝某方面功能的函数系列成为一个工具集或者包含主函数成为程序的入口。
object后面定义的单例对象名可以认为是这个单例对象的名称标签因此可以通过据点符号访问单例对象的成员也可以赋值给一个变量。
scala object B {val b a singleton object}
// defined object B
scala B.b
val res33: String a singleton object
scala val x B
val x: B.type B$3c4f0087
scala x.b
val res34: String a singleton object
定义一个类就定义了一个类型但定义单例对象并没有新产生一种类型根本上来说每个单例对象的类型都是object.type伴生对象也没有定义类型而是由伴生类定义的。但是不同的object定义之间并不能互相赋值它可以继承自超类或混入特质因此定义的两个object对象并不是相同的类型
scala object X
// defined object X
scala object Y
// defined object Y
scala var x X
var x: X.type X$304b2629
scala x Y
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |x Y| ^| Found: Y.type| Required: X.type|| longer explanation available when compiling with -explain
1 error found
3.1.7工厂对象与工厂方法
如果定义一个专门用来构造某一个类的对象的方法那么这种方法被称为工厂方法包含这些工厂方法集合的单例对象称为工厂对象。一般工厂对象会定义在伴生对象中使用工厂方法的好处是可以不用直接使用new来实例化对象改用方法调用并且方法名是任意的对外隐藏了类的实现细节。
首先我们创建一个students.scala的文件在里面写入以下内容
class Students(val name: String, var score: Int) {def exam(s:Int) score soverride def toString name s score is score .
}
object Students {def registerStu(name: String, score:Int) new Students(name,score)
}
之后编译这个文件
jiaJ-MateBookEGo:~/scala_test$ vim students.scala
jiaJ-MateBookEGo:~/scala_test$ scalac students.scala
按照书上的方法直接启动scala并使用import Students._导入会报错
scala import Students._
-- [E006] Not Found Error: ---------------------------------------------------------------------------------------------
1 |import Students._| ^^^^^^^^| Not found: Students|| longer explanation available when compiling with -explain
1 error found
这个时候我们需要添加class的路径假设我们现在处于students.scala文件的路径下经过编译会生成后缀是.class的文件如果我们在这个文件的同路径下使用这个代码导入class
scala -classpath .
如果要添加其他路径的类使用如下代码
scala -classpath /path/to/classes
执行完这个指令后会直接进入scala解释器使用如下代码调用
scala import Students._
scala val stu registerStu(Tim,100)
val stu: Students Tims score is 100.
其中object定义的对象称为工厂对象其中def定义的函数registerStu是工厂方法。
3.1.8 apply方法
apply方法是一个特殊名字的方法如果定义了这个方法可以显式调用 对象.apply(参数)也可以隐式调用 对象(参数)如果apply是无参方法应该写出空括号。通常在伴生对象中定义名为apply的工厂方法就能通过 伴生对象名(参数)来构造一个对象。也经常在类中定义一个与类相关具有特定行为的apply方法。
我们在students2.scala中编写如下代码
class Students2(val name:String, var score: Int) {def apply(s:Int) score sdef display() println(Current core is score .)override def toString name s score is score .
}
object Students2 {def apply(name: String, score: Int) new Students2(name, score)
}
执行编译指令并添加库路径这一步在之后不再赘述
jiaJ-MateBookEGo:~/scala_test$ vim students2.scala
jiaJ-MateBookEGo:~/scala_test$ scalac students2.scala
jiaJ-MateBookEGo:~/scala_test$ scala -classpath .
在解释器中执行如下代码
scala val stu2 Students2(Jack,60)//隐式调用伴生对象中的工厂方法
val stu2: Students2 Jacks score is 60.
scala stu2(80)//隐式调用类的apply方法
scala stu2.display()
Current core is 80.
3.1.9主函数
主函数是Scala程序的唯一入口程序是从主程序开始执行的。要提供这样的入口则必须在某个单例对象中定义一个名为main的函数而且该函数只有一个参数类型为字符串Array[String]函数的返回类型是Uint。任何符合条件的单例对象都能成为程序的入口。
编写一个main.scala文件将其与之前编写的students2.scala一起编译
//Start.scala
object Start {def main(args:Array[String]) {try {val score args(1).toIntval s Students2(args(0), score)println(s.toString)} catch {case ex: ArrayIndexOutOfBoundsException println(Arguments are deficient!)case ex: NumberFormatException println(Second argument must be a Int!)}}
}
编译和执行指令
jiaJ-MateBookEGo:~/scala_test$ scala Start.scala students2.scala -- Tom
Arguments are deficient!
jiaJ-MateBookEGo:~/scala_test$ scala Start.scala students2.scala -- Tom aaa
Second argument must be a Int!
jiaJ-MateBookEGo:~/scala_test$ scala Start.scala students2.scala -- Tom 100
Toms score is 100.