本文部分参考自:https://blog.csdn.net/dataiyangu/article/details/98482587
Scala第六天——面向对象编程
自己的话:漆黑的黑夜 表示着威胁 我选择诙谐
工作在堆叠 没兑现归结于那些理解
Scala对象之单例对象、伴生对象、Apply 方法、应用程序对象、枚举
一、单例对象
1.简述:
(1)object,相当于class的单个实例,通常在里面放一些静态的field或者method
(2)第一次调用object的方法时,就会执行object的constructor,也就是object内部不在method中的代码;但是object不能定义接受参数的constructor
(3)注意,object的constructor只会在其第一次被调用时执行一次,以后再次调用就不会再次执行constructor了
(4)object通常用于作为单例模式的实现,或者放class的静态成员,比如工具方法
object Person {
private var eyeNum = 2
println("this Person object!")
def getEyeNum = eyeNum
}
2.详解:
Scala 中没有静态方法和静态字段, 你可以用 object 这个语法结构来达到 同样的目的。
object Accounts {
println("init")
private var lastNumber = 0
def newUniqueNumber() = { lastNumber += 1; lastNumber } }
Accounts.newUniqueNumber()
Accounts 是一个类,object Accounts合在一起是一个单例类,意思就是只会实例化一次,定义了一个.newUniqueNumber()方法,这个时候通过Accounts.newUniqueNumber()就可以调用它,这和调用一个静态方法的效果是类似的。
对象的构造器在该对象第一次使用时调用。如果对象没有使用过,他的构造器也不会被执行。
对象基本具有类的所有特性,就是一点, 你不能设置构造器的参数。
![](https://img.laitimes.com/img/9ZDMuAjOiMmIsIjOiQnIsICM38FdsYkRGZkRG9lcvx2bjxiNx8VZ6l2cs0TPB1UMjpXTzEFVOBDOsJGcohVYsR2MMBjVtJWd0ckW65UbM5WOHJWa5kHT20ESjBjUIF2X0hXZ0xCMx81dvRWYoNHLrdEZwZ1Rh5WNXp1bwNjW1ZUba9VZwlHdssmch1mclRXY39CXldWYtlWPzNXZj9mcw1ycz9WL49zZuBnL4IDO0UjN1QTM0IDMxkTMwIzLc52YucWbp5GZzNmLn9Gbi1yZtl2Lc9CX6MHc0RHaiojIsJye.png)
二、伴生对象
1.简述:
(1)如果有一个class,还有一个与class同名的object,那么就称这个object是class的伴生对象,class是object的伴生类
(2)伴生类和伴生对象必须存放在一个.scala文件之中
(3)伴生类和伴生对象,最大的特点就在于,互相可以访问private field
object Person {
private val eyeNum = 2
def getEyeNum = eyeNum
}
class Person(val name: String, val age: Int) {
def sayHello = println("Hi, " + name + ", I guess you are " + age + " years old!" + ", and usually you must have " + Person.eyeNum + " eyes.")
}
2.详解:
Java 中会有类既有实例方法又有静态方法的类。Scala 中可以通过伴生对象进行实现。
class Account {
val id = Account.newUniqueNumber()
private var balance = 0.0
def deposit(amount: Double) { balance += amount }
def description = "Account " + id + " with balance " + balance
}
object Account { // The companion object
private var lastNumber = 0
private def newUniqueNumber() = { lastNumber += 1; lastNumber }
}
val acct1 = new Account
val acct2 = new Account
acct1.deposit(1000)
val d1 = acct1.description
val d2 = acct2.description
如果定义了一个Account对象,然后通过object Account 定义了一次,那么Account这个实例是可以直接用的,就像上述代码中class Account中的 val id = Account.newUniqueNumber(),上面代码中的def description = "Account " + id + " with balance " + balance,这里的id就是通过静态方法得到。
其实还是上面的单例对象。
类和它的伴生对象可以相互访问私有特性,他们必须存在同一个源文件 中。必须同名
3.让object继承抽象类
(1)object的功能其实和class类似,除了不能定义接受参数的constructor之外
(2)object也可以继承抽象类,并覆盖抽象类中的方法
abstract class Hello(var message: String) {
def sayHello(name: String): Unit
}
object HelloImpl extends Hello("hello") {
override def sayHello(name: String) = {
println(message + ", " + name)
}
}
HelloImpl.sayHello("xiaoming")
打印:Hello,xiaoming
三、Apply方法
1.简述:
我们通常会定义和使用对象的 apply 方法,当遇到如下形式时: Object(参数 1、参数 2、参数…)会调用 apply 方法。Apply 方法一般都声明在伴生对象中。
class Account private (val id: Int, initialBalance: Double) { private var balance = initialBalance
def deposit(amount: Double) { balance += amount }
def description = "Account " + id + " with balance " + balance
}
object Account { // The companion object def apply(initialBalance: Double) =
new Account(newUniqueNumber(), initialBalance)
private var lastNumber = 0
private def newUniqueNumber() = { lastNumber += 1; lastNumber }
}
2.详解:
(1)object中非常重要的一个特殊方法,就是apply方法
(2)通常在伴生对象中实现apply方法,并在其中实现构造伴生类的对象的功能
(3)而创建伴生类的对象时,通常不会使用new Class的方式,而是使用Class()的方式,隐式地调用伴生对象得apply方法,这样会让对象创建更加简洁
// 比如,Array类的伴生对象的apply方法就实现了接收可变数量的参数,并创建一个Array对象的功能
val a = Array(1, 2, 3, 4, 5)
// 比如,定义自己的伴生类和伴生对象
class Person(val name: String)
object Person {
def apply(name: String) = new Person(name)
}
四、应用程序对象(main方法)
1.简述:
(1)每一个 Scala 应用程序都需要从一个对象的 main 方法开始执行,这个方
法的类型为 Array[String]=>Unit。
object Hello {
def main(args: Array[String]) {
println("Hello, World!")
}
}
(2)或者扩展一个 App 特质:
object Hello extends App {
if (args.length > 0)
println("Hello, " + args(0))
else
println("Hello, World!")
}
2.详解:
(1)就如同java中,如果要运行一个程序,必须编写一个包含main方法类一样;在scala中,如果要运行一个应用程序,那么必须有一个main方法,作为入口
// scala中的main方法定义为def main(args: Array[String]),而且必须定义在object中
object HelloWorld {
def main(args: Array[String]) {
println("Hello World!!!")
}
}
(2)在桌面创建一个HelloWorld.scala,内容如上,在windows上进入cmd,执行scalac HelloWorld.scala编译scala文件 ,产生一个HelloWorld.class,然后scala HelloWorld
(3)除了自己实现main方法之外,还可以继承App Trait,然后将需要在main方法中运行的代码,直接作为object的constructor代码;而且用args可以接受传入的参数
object HelloWorld extends App {
if (args.length > 0) println("hello, " + args(0))
else println("Hello World!!!")
}
(4)如果要运行上述代码,需要将其放入.scala文件,然后先使用scalac编译,再用scala执行
scalac HelloWorld.scala
scala -Dscala.time HelloWorld
(5)App Trait的工作原理为:App Trait继承自DelayedInit Trait,scalac命令进行编译时,会把继承App Trait的object的constructor代码都放到DelayedInit Trait的delayedInit方法中执行
五、枚举
1.简述;
(1)Scala没有直接提供类似于Java中的Enum这样的枚举特性,如果要实现枚举,则需要用object继承Enumeration类,并且调用Value方法来初始化枚举值
object Season extends Enumeration {
val SPRING, SUMMER, AUTUMN, WINTER = Value
}
(2)还可以通过Value传入枚举值的id和name,通过id和toString可以获取; 还可以通过id和name来查找枚举值
object Season extends Enumeration {
val SPRING = Value(0, "spring")
val SUMMER = Value(1, "summer")
val AUTUMN = Value(2, "autumn")
val WINTER = Value(3, "winter")
}
Season(0)
Season.withName("spring")
(3)使用枚举object.values可以遍历枚举值
2.详解:
Scala 中没有枚举类型,定义一个扩展 Enumeration 类的对象,并以 value
调用初始化枚举中的所有可能值。
object TrafficLightColor extends Enumeration {
val Red = Value(0, "Stop")
val Yellow = Value(10) // Name "Yellow"
val Green = Value("Go") // ID 11
}
TrafficLightColor.Red
//访问id
TrafficLightColor.Red.id
//访问value
TrafficLightColor.Red.toString
在传入的时候可以把id 和 vallue 都传进去,也可以之传入id或者只传入value,如果之传入id的话,name就是value,也就是前面的名字,如果传入名称但是没有传入id的话,id是顺延的,上一个是10,这里就会是11