一、单例对象

### --- 单例对象

~~~ Scala并没有提供Java那样的静态方法或静态字段;
~~~ 可以采用object关键字实现单例对象,具备和Java静态方法同样的功能;
~~~ 使用object语法结构【object是Scala中的一个关键字】达到静态方法和静态字段的目的;
~~~ 对象本质上可以拥有类的所有特性,除了不能提供构造器参数;
### --- 对于任何在Java中用单例对象的地方,在Scala中都可以用object实现:

~~~ 作为存放工具函数或常量的地方
~~~ 高效地共享单个不可变实例
### --- 代码示例

class Session {
def hello(first: Int): Int = {
println(first)
first
}
}
object SessionFactory {
val session = new Session
def getSession(): Session = {
session
}
def main(args: Array[String]): Unit = {
for (x <- 1 to 10) {
//通过直接调用,产生的对象都是单例的
val session = SessionFactory.getSession()
println(session)
}
}
}
### --- Scala中的单例对象具有如下特点:

~~~ 创建单例对象不需要使用new关键字
~~~ object中只有无参构造器
~~~ 主构造代码块只能执行一次,因为它是单例的
object ObjectDemo {
println("这是单例对象的代码!")
def main(args: Array[String]): Unit = {
val object1=ObjectDemo
val object2=ObjectDemo
}
}

二、编程代码实现

### --- 编程代码

package yanqi.cn.part04

object Object {
println("这是单例对象的代码!")

def printInfo: Unit = {
println("Hello Scala Object!")
}
}

object ObjectDemo {
def main(args: Array[String]): Unit = {
// val object1=Object
// val object2=Object

Object.printInfo
Object.printInfo
}
}
### --- 编译打印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55788:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part04.ObjectDemo
这是单例对象的代码!
Hello Scala Object!
Hello Scala Object!

Process finished with exit code 0

三、伴生类与伴生对象

### --- 伴生类与伴生对象

~~~ 当单例对象与某个类具有相同的名称时,它被称为这个类的“伴生对象”;
~~~ 类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法);
### --- 编程代码示例

class ClassObject {
val id = 1
private var name = "yanqi"
def printName(): Unit ={
//在ClassObject类中可以访问伴生对象ClassObject的私有字段
println(ClassObject.CONSTANT + name )
}
}

object ClassObject{
//伴生对象中的私有字段
private val CONSTANT = "汪汪汪"
def main(args: Array[String]) {
val p = new ClassObject
//访问伴生类的私有字段name
p.name = "123"
p.printName()
}
}

四、编程实现

### --- 编程代码

package yanqi.cn.part04

//伴生类和伴生对象,它们的名字是一样的,并且必须存在于同一文件中
class ClassObject {
private var name = "yanqi"

def printInfo: Unit = {
//在伴生类中可以访问伴生对象的私有成员
println(ClassObject.num)
println("Hello Object!")
}
}

object ClassObject {
private val num = 10

def main(args: Array[String]): Unit = {
val classObject = new ClassObject
//在伴生对象中可以访问伴生类的私有成员
println(classObject.name)
classObject.printInfo
}
}
### --- 编译打印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55965:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part04.ClassObject
yanqi
10
Hello Object!

Process finished with exit code 0

五、应用程序对象

### --- 应用程序对象

~~~ 每个Scala应用程序都必须从一个对象的main方法开始,
~~~ 这个方法的类型为 Array[String] => Unit;
~~~ 备注:main方法写在class中是没有意义的,
~~~ 在IDEA中这样的 class 连run的图标都不能显示
~~~ 除了main方法以外,也可以扩展App特质(trait)
### --- 编程示例

object Hello extends App {
if (args.length > 0)
println(s"Hello World; args.length = ${args.length}")
else
println("Hello World")
}

六、编程实现

### --- 编程代码

package yanqi.cn.part04

object AppDemo extends App {
println("Hello Spark!")
}
### --- 编译打印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=55989:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part04.AppDemo
Hello Spark!

Process finished with exit code 0

七、apply方法

### --- apply方法:

~~~ object 中有一个非常重要的特殊方法 -- apply方法;
~~~ apply方法通常定义在伴生对象中,
~~~ 目的是通过伴生类的构造函数功能,来实现伴生对象的构造函数功能;
~~~ 通常我们会在类的伴生对象中定义apply方法,当遇到类名(参数1,...参数n)时apply方法会被调用;
~~~ 在创建伴生对象或伴生类的对象时,通常不会使用new class/class() 的方式,
~~~ 而是直接使用class()隐式的调用伴生对象的 apply 方法,这样会让对象创建的更加简洁;
### --- 编程示例

//class Student为伴生类
class Student(name: String, age: Int) {
private var gender: String = _
def sayHi(): Unit ={
println(s"大家好,我是$name,$gender 生")
}
}

//object Student是class class的伴生对象
object Student {

//apply方法定义在伴生对象中
def apply(name: String, age: Int): Student = new Student(name, age)
def main(args: Array[String]): Unit = {

//直接利用类名进行对象的创建,这种方式实际上是调用伴生对象的apply方法实现的
val student=Student("jacky",30)
student.gender="男"
student.sayHi()
}
}
### --- 问题:在Scala中实现工厂方法,让子类声明哪种对象应该被创建,保持对象创建在同一位置。

~~~ 例如,假设要创建Animal工厂,让其返回Cat和Dog类的实例,基于这个需求,
~~~ 通过实现Animal伴生对象的apply方法,工厂的使用者可以像这样创建新的Cat和Dog实例。


abstract class Animal {
def speak
}
class Dog extends Animal {
override def speak: Unit = {
println("woof")
}
}

class Cat extends Animal {
override def speak: Unit = {
println("meow")
}
}
object Animal {
def apply(str: String): Animal = {
if (str == "dog")
new Dog
else
new Cat
}
def main(args: Array[String]): Unit = {
val cat = Animal("cat")
cat.speak
val dog = Animal("dog")
dog.speak
}
}

八、编程实现

### --- 编程代码

package yanqi.cn.part04

class Student(name: String, age: Int) {
private var gender: String = _

def sayHi(): Unit = {
println(s"大家好,我是$name,$gender 生")
}
}

object Student {
//apply方法需要定义在伴生对象中
def apply(name: String, age: Int): Student = new Student(name, age)

def main(args: Array[String]): Unit = {
//直接使用class(参数...)这种方式隐式调用伴生对象中的apply方法来创建class Student对象
val student = Student("jacky", 30)
//伴生类与伴生对象可以相互访问私有成员
student.gender = "男"

student.sayHi()
}
}
### --- 编译打印

D:\JAVA\jdk1.8.0_231\bin\java.exe "-javaagent:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=56017:D:\IntelliJIDEA\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\JAVA\jdk1.8.0_231\jre\lib\charsets.jar;D:\JAVA\jdk1.8.0_231\jre\lib\deploy.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\access-bridge-64.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\cldrdata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\dnsns.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jaccess.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\jfxrt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\localedata.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\nashorn.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunec.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunjce_provider.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunmscapi.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\sunpkcs11.jar;D:\JAVA\jdk1.8.0_231\jre\lib\ext\zipfs.jar;D:\JAVA\jdk1.8.0_231\jre\lib\javaws.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jce.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfr.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jfxswt.jar;D:\JAVA\jdk1.8.0_231\jre\lib\jsse.jar;D:\JAVA\jdk1.8.0_231\jre\lib\management-agent.jar;D:\JAVA\jdk1.8.0_231\jre\lib\plugin.jar;D:\JAVA\jdk1.8.0_231\jre\lib\resources.jar;D:\JAVA\jdk1.8.0_231\jre\lib\rt.jar;E:\NO.Z.10000——javaproject\NO.Z.00002.Hadoop\ScalaPro\out\production\ScalaPro;D:\JAVA\scala-2.12.2\lib\scala-library.jar;D:\JAVA\scala-2.12.2\lib\scala-reflect.jar yanqi.cn.part04.Student
大家好,我是jacky,男 生

Process finished with exit code 0

Walter Savage Landor:strove with none,for none was worth my strife.Nature I loved and, next to Nature, Art:I warm'd both hands before the fire of life.It sinks, and I am ready to depart

                                                                                                                                                   ——W.S.Landor