Scala编程理论知识
类、构造器、object、main、apply
第一个Scala的HelloWorld程序
HelloWorld.scala
object HelloWorld {
def main(args: Array[String]): Unit = {
println("Hello World!");
}
}
Scala面向对象编程第一个demo
Person.scala
class Person {
private val id = 10
// val修饰的常量,只可以查看值,相当于java final修饰,只有getter方法
val age = 20
// var修饰的常量,可以修改可以查看,既有setter,又有getter
var num = 30
def sayHelloComplex() = {
println("hello")
}
def sayHello = println("hello")
}
Test.scala
// object相当于java中static修饰的含义,里面的方法和属性不需要new就可以直接调用
// object是全局单例,只有一个唯一的实例,因此把main方法写在object中作为程序的入口
object Test {
def main(args: Array[String]): Unit = {
val person = new Person
// println(person.id) 不能访问私有变量
println(person.age)
println(person.num)
// person.age=30 不能修改val修饰的常量
person.num = 40
println(person.num)
person.sayHello
}
}
20
30
40
hello
Scala面向对象编程第二个demo
Session.scala
class Session {
}
// 因为object中属性和方法都是静态的特性,所以可以把通用的方法定义在object变成通用的工具类
// 该部分相当于java中的静态代码块
object SessionFactory {
val session = new Session
// 在object中的方法相当于java中的静态方法
def getSession: Session = this.session
}
TestObject.scala
object TestObject {
def main(args: Array[String]): Unit = {
// 通过new获取对象实例
val session1 = new Session
// 单例对象,不需要new,通过类名.属性获取实例
val session2 = SessionFactory.session
// 单例对象,不需要new,通过类名.方法获取实例
val session3 = SessionFactory.getSession
println(session1)
println(session2)
println(session3)
}
}
site.zhansiyu.scala.Session@47f37ef1
site.zhansiyu.scala.Session@5a01ccaa
site.zhansiyu.scala.Session@5a01ccaa
1. 类
类是对象的抽象,而对象是类的具体实例。类是抽象的,不占用内存,而对象是具体的,占用存储空间。
如果没有指定访问修饰符,默认情况下,Scala对象的访问级别都是public。
类私有字段private,只能在类的内部使用或者伴生对象中访问。
类私有字段private[this],在伴生对象里面也不可以访问。
2. 构造器
与java构造不同之处在于Scala不需要定义与类名相同的方法作为构造器。
主构造器:主构造器的参数直接放置类名后面,与类交织在一起。主构造器会执行类定义的所有语句,所以,一个Scala类中,除了参数、方法以外的代码都是主构造的内容。
辅助构造器:都以def this开始。每个辅助构造器执行必须以主构造器或者其他辅助构造器的调用开始。
每个类都有主构造器,主构造器的参数直接设置类名后面,与类交织在一起。
主构造器会执行类定义的所有语句。
每个辅助构造器执行必须以主构造器或者其它辅助构造器的调用开始。
// 主构造器定义在类的名称后面,参数列表与类名交织在一起
// 主构造器的参数会自动提升为对象的属性,不需要在对象中重新定义一遍
class Student(val name: String, val age: Int) {
// 在类的定义中,除了方法和属性外,都是主构造器的一部分
println("主构造器开始执行")
private var id = 1
// private[x] 作用域保护 除了x之外,其他都是private的
// private[this] 除了自己,其它(包括伴生对象)都是private
private[this] var gender = "male"
def sayHello = println("hello:" + name + " id=" + id + " age=" + age + " gender=" + gender)
println("主构造器结束执行")
// 定义辅助构造器
def this(name: String, age: Int, id: Int, gender: String) {
// 定义辅助构造器的第一行必须调用主构造器或者其他已经存在的辅助构造器
this(name, age)
this.id = id
println("执行辅构造器")
}
}
object Student {
def main(args: Array[String]): Unit = {
// 以主构造器创建对象实例
val s1 = new Student("zs", 20)
// s1.gender 不能访问
s1.sayHello
// 以辅助构造器创建对象实例
val s2 = new Student("ls", 25, 2, "female")
s2.sayHello
}
}
3. Scala 中的 object
scala 中没有 static 关键字,所以对于一个 class 来说,所有的方法和成员变量在实例被 new 出来之前都是无法访问的,因此在 class 中的写 main 方法没什么用了。无法调用执行。为此 scala 提供了 object,相当于 class 的单个实例。可以直接访问,不需要实例化该类的对象。因此 main 方法可以写在 object 中,作为程序启动的入口。
在 object 中,属性、方法相当于都是静态的。
object 作用:存放工具方法和常量、高效共享单个不可变的实例、单例模式等。
用【单例对象名称.变量】获取实例
用【单例对象名称.方法】获取实例
class 普通对象 需要new 获取对象的实例 通过实例调用对象的属性和方法
object 全局唯一实例对象 不需要new 里面方法和属性都是静态的 直接类名.方法 类名.属性
通常把main方法写在object中 作为程序的入口
- 伴生类 & 伴生对象
如果有一个 class 文件,还有一个与 class 同名的 object 文件,那么就称这个 object 是 class 的伴生对象,class 是 object 的伴生类;伴生类和伴生对象必须存放在一个.scala 文件中;伴生类和伴生对象的最大特点是,可以相互访问(包括 private 属性 除非属性被[this]修饰)
// 在同一个.scala文件中,class名字和object名字一样,就说两者产生了伴生关系
// 类叫对象的伴生类,对象叫类的伴生对象
// 伴生关系的类和对象可以互相访问对象的私有属性
// 伴生类
class ClassAndObject {
private val id: Int = 20
private[this] val num: Int = 30
}
// 伴生对象
object ClassAndObject {
def main(args: Array[String]): Unit = {
val co = new ClassAndObject
println(co.id)
// println(co.num) 当使用private[this]修饰时,不可访问
}
}
4. main方法
同 Java 一样,如果要运行一个程序,必须要编写一个包含 main 方法的类;
在 Scala 中,也必须要有一个 main 方法,作为入口;
Scala 中的 main 方法定义为 def main(args: Array[String]),而且必须定义在 object 中;
除了自己实现 main 方法之外,还可以继承 App Trait,然后,将需要写在 main 方法 中运行的代码,直接作为 object 的 constructor 代码即可,而且还可以使用 args 接收传入的参数
// 在object中定义main方法
object MainDemo {
def main(args: Array[String]): Unit = {
if (args.length > 0)
print("hello:" + args(0))
else
print("hello")
}
}
// 使用继承App Trait,将需要写在main方法中运行的代码直接作为object的constructor代码即可。而且还可以使用args接收传入的参数
object AppDemo extends App {
if (args.length > 0)
print("hello:" + args(0))
else
print("hello")
}
5.apply方法
object 中非常重要的一个特殊方法,就是 apply 方法;
apply 方法通常是在伴生对象中实现的,其目的是,通过伴生类的构造函数功能,来实现伴生对象的构造函数功能;
通常我们会在类的伴生对象中定义 apply 方法,当遇到类名(参数 1,…参数 n)时 apply 方法会被调用;
在创建伴生对象或伴生类的对象时,通常不会使用 new class/class() 的方式,而是直接使用 class(),隐式的调用伴生对象的 apply 方法,这样会让对象创建的更加简洁;
/**
* 源码:xs表示可变参数
* Array类的伴生对象中,就实现了可接受变长参数的apply方法,
* 并通过创建一个Array类的实例化对象,实现了伴生对象的构造函数功能
* /** Creates an array of `Int` objects */
* // Subject to a compiler optimization in Cleanup, see above.
* def apply(x: Int, xs: Int*): Array[Int] = {
* val array = new Array[Int](xs.length + 1)
* array(0) = x
* var i = 1
* for (x <- xs.iterator) { array(i) = x; i += 1 }
* array
* }
*/
object TestArray {
def main(args: Array[String]): Unit = {
val arr1 = new Array[Int](4)
// apply方法是Scala中特殊的方法,某种程度可以理解为是class的一种构造方法,通过apply可以创建对象实例
// apply方法必须定义在类的伴生对象中
// 在创建对象的实例的时候,如果不加new,此时就会去伴生对象中寻找有没有apply方法,如果有调用,如果没有报错
val arr2 = Array(1, 2, 3, 4, 5)
}
}
apply方法有点类似于java中的构造函数,接收构造参数变成一个对象。
class Cat(name: String) {
}
// 伴生对象
object Cat {
def apply(name: String): Cat = new Cat(name)
}
object Test {
def main(args: Array[String]): Unit = {
// 通过new创建的
val xiaobai = new Cat("xiaobai")
// 底层调用apply方法,得到Cat类型的对象
val xiaohei = Cat("xiaohei")
}
}
扩展:unapply方法 接受一个对象,从对象中提取出相应的值
class Money(val value: Double, val country: String) {
}
object Money {
def apply(value: Double, country: String): Money = new Money(value, country)
def unapply(money: Money): Option[(Double, String)] = {
if (money == null)
None
else
Some(money.value, money.country)
}
}
object MoneyTest {
def main(args: Array[String]): Unit = {
val money = Money(15.5, "RMB")
money match {
case Money(num, coutry) => print(s"The price is $num$coutry.")
case _ => print("no price")
}
}
}