1- 类

1.1- 简介:类、方法及对象

类是用来创建对象的蓝图。
Scala文件中包含的多个类之间,都是彼此可见的,不需要声明为public。
创建对象
定义好类以后,就可以使用new关键字来创建对象。
  • 字段默认为public,在类外部和内部都可以访问该字段。
  • 私有字段使用private关键字修饰,外界无法访问,只有在类内部可以访问该字段。
方法
  • 通过def关键字实现方法的定义
  • 方法的返回值:方法里面的最后一个表达式的值就是方法的返回值,不需要靠return语句。
  • 如果方法不返回任何值,返回值的类型就为Unit。
  • 如果包含方法具体操作语句的大括号里面只有一行语句,可以省略大括号。
package testscala

object TestScala {
def main(args: Array[String]) {
println("Testing, Scala!") val myTest1 = new myCounter
myTest1.increment()
// myTest1.increment // 调用无参方法时,可以省略方法名后面的圆括号
println(myTest1.current) val myTest2 = new myCounter2
myTest2.increment(5)
println(myTest2.current)
} } class myCounter {
private var value = 0
def increment(): Unit = { value += 1 }
// def increment(): Unit = value += 1 // 大括号里面只有一行语句,可以省略大括号
def current(): Int = { value }
} class myCounter2 {
private var value = 0
def increment(step: Int): Unit = { value += step }
def current(): Int = { value }
}

1.2- 定义类似getter和setter的方法

Scala没有提供getter和setter方法,但可以通过定义类似getter和setter的方法,来访问私有value字段。
package testscala

object TestScala {
def main(args: Array[String]) {
println("Testing, Scala!") val myTest3 = new myCounter3
println(myTest3.value)
myTest3.value = 3
println(myTest3.value)
myTest3.increment(1)
println(myTest3.current) val myTest4 = new myCounter4
println(myTest4.value)
myTest4.value = 3
println(myTest4.value)
myTest4.increment(1)
println(myTest4.current)
}
} class myCounter3 {
var value = 0 // 变量默认为public,对外部可见
def increment(step: Int): Unit = { value += step }
def current(): Int = { value }
} class myCounter4 {
private var privateValue = 0 // 变量为private,私有字段
def value = privateValue
def value_=(newValue: Int) {
if (newValue > 0) privateValue = newValue // 新值为正数才可以修改
}
def increment(step: Int): Unit = { value += step }
def current(): Int = { value }
}

1.3- 构造器

Scala构造器包含1个主构造器和若干个(0个或多个)辅助构造器。
主构造器
Scala的每个类都有主构造器。
Scala的主构造器是整个类体,需要在类名称后面罗列出构造器所需的所有参数,这些参数被编译成字段,字段的值就是创建对象时传入的参数的值。
package helloscala

object helloscala {
def main(args: Array[String]) {
println("Testing, Scala!") val myTest5 = new myCounter5("Timer", 2)
myTest5.info
myTest5.increment(1)
printf("Current Value is: %d\n", myTest5.current)
}
} class myCounter5(val name: String, val mode: Int) {
private var value = 0
def increment(step: Int): Unit = { value += step }
def current(): Int = { value }
def info(): Unit = { printf("Name:%s and mode is %d \n", name, mode) }
}
辅助构造器
辅助构造器的名称为this。
每个辅助构造器都必须调用一个此前已经定义的辅助构造器或主构造器。
package helloscala

object helloscala {
def main(args: Array[String]) {
println("Testing, Scala!") val myTest6 = new myCounter6
myTest6.info
myTest6.increment(1)
printf("Current Value is: %d\n", myTest6.current) val myTest62 = new myCounter6("Runner")
myTest62.info
myTest62.increment(2)
printf("Current Value is: %d\n", myTest62.current) val myTest63 = new myCounter6("Timer", 2)
myTest63.info
myTest63.increment(3)
printf("Current Value is: %d\n", myTest63.current)
}
} class myCounter6 {
private var value = 0
private var name = ""
private var mode = 1
def this(name: String) {
this()
this.name = name
}
def this(name: String, mode: Int) {
this(name)
this.mode = mode
}
def increment(step: Int): Unit = { value += step }
def current(): Int = { value }
def info(): Unit = { printf("Name:%s and mode is %d \n", name, mode) }
}

2- 面向对象-对象

2.1- 单例对象

Scala并没有提供Java那样的静态方法或静态字段。
但可以用object关键字定义单例对象,具备和Java静态方法同样的功能。
package helloscala

object helloscala {
def main(args: Array[String]) {
println("Testing, Scala!")
printf("The first person id is %d.\n", Person.newPersonId())
printf("The second person id is %d.\n", Person.newPersonId())
printf("The third person id is %d.\n", Person.newPersonId())
}
} object Person {
private var lastId = 0
def newPersonId() = {
lastId += 1
lastId
}
}

2.2- 伴生对象

在Scala中通过伴生对象来实现同时包含实例方法和静态方法的类。
当单例对象与某个类具有相同的名称时,它被称为这个类的“伴生对象”。
类和它的伴生对象必须存在于同一个文件中,而且可以相互访问私有成员(字段和方法)。
Scala源代码经过编译后都会变成JVM字节码,class和object在Java层面都会被合二为一。class里面的成员成了实例成员,object成员成了static成员。
伴生类中的成员和伴生对象中的成员都被合并到一起,并且伴生对象中的方法成为静态方法。
package testscala

object TestScala { // 单例对象与某个类具有相同的名称,称为这个类的伴生对象

  private var lastId = 0
private def newPersonId() = {
lastId += 1
lastId
} def main(args: Array[String]) {
println("Testing, Scala!")
val person1 = new TestScala("AAA")
val person2 = new TestScala("BBB")
person1.info()
person2.info()
}
} class TestScala {
private val id = TestScala.newPersonId() //调用伴生对象中的方法
private var name = "" def this(name: String) {
this()
this.name = name
} def info() { printf("The id of %s is %d.\n", name, id) }
}
 注意:
可以通过javap命令对.class文件进行反编译,来确认伴生类中的成员和伴生对象中的成员都被合并到一起,并且,伴生对象中的方法成为静态方法。
另外,进行反编译时,要把伴生对象中方法的private修饰符去掉。如果不去掉,作为伴生对象的私有方法,在javap反编译后,在执行结果中是看不到这个方法的。

2.3- 应用程序对象

每个Scala应用程序都必须从一个对象的main方法开始。
第一种方法:直接使用scala命令运行得到结果。
代码中没有定义类,就是一个单例对象,因此,可以不用编译,直接使用scala命令运行得到结果。
guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ ls -l
total 1
-rw-r--r-- 1 guowli 1049089 88 Nov 21 11:31 test.scala guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ cat test.scala
object HelloWorld {
def main(args: Array[String]){
println("Hello, World!")
}
} guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ scala test.scala
Hello, World! guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ ls -l
total 1
-rw-r--r-- 1 guowli 1049089 88 Nov 21 11:31 test.scala guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$

第二种方法:先编译再执行

首先使用scalac编译命令对.scala文件进行编译,然后使用scala命令运行。
guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ scalac test.scala guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ ls -l
total 3
-rw-r--r-- 1 guowli 1049089 665 Nov 21 11:33 'HelloWorld$.class'
-rw-r--r-- 1 guowli 1049089 602 Nov 21 11:33 HelloWorld.class
-rw-r--r-- 1 guowli 1049089 88 Nov 21 11:31 test.scala guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$ scala -classpath . HelloWorld
Hello, World! guowli@5CG450158J MINGW64 /d/Anliven-Running/Zen/ScalaProjets/temptest
$

2.4- apply方法和update方法

apply方法
用括号传递给变量(对象)一个或多个参数时,Scala 会把它转换成对apply方法的调用
类中定义apply方法:
package testscala

object TestScala {
def main(args: Array[String]) {
println("Testing, Scala!")
val myObject = new TestApplyClass
println(myObject("param1")) // 执行myObject("param1")时调用了apply方法
}
} class TestApplyClass {
def apply(param: String): String = {
println("apply method called, parameter is: " + param)
"Hello World!" // apply方法的返回值
}
}

单例对象中定义apply方法:

package testscala

object TestScala {

  def main(args: Array[String]) {
println("Testing, Scala!")
val group = TestScala("AAA", "BBB") // 调用了apply方法,获得返回值并赋值给变量
println(group)
} def apply(param1: String, param2: String): String = {
println("apply method called")
param1 + " and " + param2 // 方法的返回值
} }

伴生类和伴生对象中的apply方法:

package testscala

object TestScala {
def main(args: Array[String]) {
val a = ApplyTest() // 调用伴生对象中的apply方法并返回该方法调用的值
a.greetingOfClass
a() // 调用伴生类中的apply方法
}
} object ApplyTest {
def apply() = {
println("apply method in object is called")
new ApplyTest() // 返回ApplyTest类的实例化对象
}
} class TestScala {
} class ApplyTest {
def apply() = println("apply method in class is called!")
def greetingOfClass: Unit = {
println("Greeting method in class is called.")
}
}

示例:apply方法

 val myStrArr = Array("AAA", "BBB", "CCC")       //> myStrArr  : Array[String] = Array(AAA, BBB, CCC)
利用Scala中Array对象已定义的apply方法可以直接给对象传递参数。
也就是调用Array类的伴生对象Array的apply方法,完成数组的初始化。
理解:将伴生对象作为工厂使用,就使用关键字new创建实例化对象
package testscala

object TestScala {
def main(args: Array[String]) {
val mycar = Car("BMW") // 调用伴生对象中的apply方法创建一个Car类的实例化对象
mycar.info()
}
} class Car(name: String) {
def info() { println("Car name is " + name) }
} object Car {
def apply(name: String) = new Car(name) // 调用伴生类Car的构造方法创建一个Car类的实例化对象
}
update方法
当对带有括号并包括一到若干参数的对象进行赋值时,编译器将调用对象的update方法,把括号里的参数和等号右边的对象一起作为update方法的输入参数来执行调用。
  val myStrArr = new Array[String](3)             //> myStrArr  : Array[String] = Array(null, null, null)
myStrArr(0) = "AAA" //实际调用了伴生类Array中的update方法,执行myStrArr.update(0,"AAA")
myStrArr(1) = "BBB" //实际调用了伴生类Array中的update方法,执行myStrArr.update(1,"BBB")
myStrArr.update(2, "CCC") // 执行myStrArr.update(2,"CCC")
for (x <- myStrArr) println(x) //> AAA
//| BBB
//| CCC

注意:在进行元组赋值的时候,之所以没有采用Java中的方括号myStrArr[0],而是采用圆括号的形式,myStrArr(0),是因为存在上述的update方法的机制。

3- 面向对象-继承

Scala和Java一样,不允许类从多个超类继承。
Scala中的继承与Java有着显著的不同:
  1. 重写一个非抽象方法必须使用override修饰符。
  2. 只有主构造器可以调用超类的主构造器。
  3. 在子类中重写超类的抽象方法时,不需要使用override关键字。
  4. 可以重写超类中的字段。
抽象类
  • 使用关键字abstract定义抽象类
  • 抽象类不能直接被实例化,可以被其他类继承
  • 定义抽象类中的抽象方法不需要使用abstract关键字,方法体为空
  • 抽象类中定义的字段必须声明类型,否则编译会报错;如果字段没有初始化值,就表示是一个抽象字段
扩展类
  扩展类可以直接被实例化。
package testscala

object TestScala {
def main(args: Array[String]) {
val myCar1 = new BMWCar()
val myCar2 = new BenzCar()
myCar1.greeting()
myCar1.info()
myCar2.greeting()
myCar2.info()
}
} abstract class Car { //抽象类
val carBrand: String //抽象字段没有初始化值
def info() //抽象方法,不需要使用abstract关键字,方法体为空
def greeting() { println("Welcome to my car!") } //非抽象方法,方法体内容非空
} class BMWCar extends Car { //扩展类
override val carBrand = "BMW" //重写超类字段,需要使用override关键字,否则编译会报错
def info() { printf("This is a %s car.\n", carBrand) } //重写超类的抽象方法时,可以不使用override关键字
override def greeting() { println("Welcome to my BMW car!") } //重写超类的非抽象方法,必须使用override关键字
} class BenzCar extends Car { //扩展类
override val carBrand = "Benz"
def info() { printf("This is a %s car.\n", carBrand) }
override def greeting() { println("Welcome to my Benz car!") }
}

4- 面向对象-特质

Scala中没有接口的概念,而是提供了“特质(trait)”,不仅实现了接口的功能,还具备了很多其他的特性。
Scala中一个类只能继承自一个超类,却可以实现多个特质,通过重用特质中的方法和字段可以实现多重继承。
  • 使用关键字trait定义特质
  • 特质中没有方法体的方法,默认为抽象方法。抽象方法不需要使用abstract关键字。
  • 特质定义完成后,可以使用extends或with关键字把特质混入类中。
  • 特质可以包含具体实现,特质中的字段和方法不一定要是抽象的。
  • 如果特质只包含了抽象字段和抽象方法,相当于实现了类似Java接口的功能。
package helloscala

object helloscala {
def main(args: Array[String]) {
println("Testing, Scala!")
val myCarId1 = new BenzCarId()
val myCarId2 = new BMWCarId()
printf("My first CarId is %d.\n", myCarId1.currentId)
myCarId2.greeting("Welcome my second car.")
printf("My second CarId is %d.\n", myCarId2.currentId)
}
} trait CarId { //使用关键字trait定义特质
var id: Int //定义抽象字段
def currentId(): Int //定义抽象方法,不需要使用abstract关键字
} trait CarGreeting { //使用关键字trait定义特质
def greeting(msg: String) { println(msg) } //定义非抽象方法,
} class BenzCarId extends CarId { //使用extends关键字把特质混入类中
override var id = 10000 //BYD汽车编号从10000开始
def currentId(): Int = { id += 1; id } //返回汽车编号
} class BMWCarId extends CarId with CarGreeting { //使用extends关键字混入第1个特质,后面可以反复使用with关键字混入更多特质
override var id = 20000
def currentId(): Int = { id += 1; id }
}

Scala - 快速学习06 - 面向对象的更多相关文章

  1. Scala - 快速学习05 - 数据结构

    1- 数组(Array) 数组一般包括定长数组和变长数组. 可以不指明数组类型,Scala会自动根据提供的初始化数据来推断出数组的类型. 在Scala中,对数组元素的应用,是使用圆括号,而不是方括号. ...

  2. Scala - 快速学习01 - Scala简介

    Scala简介 Scala(Scalable Language)是一门多范式(multi-paradigm)编程语言,Scala的设计吸收借鉴了许多种编程语言的思想,具备面向对象编程.函数式编程等特性 ...

  3. scala快速学习笔记(一):变量函数,操作符,基本类型

    为了用spark,先学下scala. 参考教程:http://meetfp.com/zh/scala-basic doc查询:http://docs.scala-lang.org 其它资料:http: ...

  4. 快速学习JavaScript面向对象编程

    到处都是属性.方法,代码极其难懂,天哪,我的程序员,你究竟在做什么?仔细看看这篇指南,让我们一起写出优雅的面向对象的JavaScript代码吧! 作为一个开发者,能否写出优雅的代码对于你的职业生涯至关 ...

  5. Scala - 快速学习09 - 函数式编程:一些操作

    1- 集合类(collection) 系统地区分了可变的和不可变的集合. scala.collection包中所有的集合类 可变集合(Mutable) 顾名思义,意味着可以修改,移除或者添加一个元素. ...

  6. Scala - 快速学习08 - 函数式编程:高阶函数

    函数式编程的崛起 函数式编程中的“值不可变性”避免了对公共的可变状态进行同步访问控制的复杂问题,能够较好满足分布式并行编程的需求,适应大数据时代的到来. 函数是第一等公民 可以作为实参传递给另外一个函 ...

  7. Scala - 快速学习07 - 模式匹配

    Scala中的模式匹配的功能可以应用到switch语句.类型检查.“解构”等多种场合. 简单匹配 Scala的模式匹配最常用于match语句中.Scala的match语句类似Java里的switch. ...

  8. Scala - 快速学习04 - 求值策略

    表达式求值策略(Evaluation Strategy) Scala中所有的运算都是基于表达式的. Call By Value - 对函数实参求值,且仅求值一次:函数调用之前对所有表达式进行求值 Ca ...

  9. Scala - 快速学习03 - 基础语法

    1- 变量 变量 mutable variable 在程序运行过程中其值可能发生改变的量 关键词var定义变量,定义时直接进行求值 常量 immutable variable 在程序运行过程中其值不会 ...

随机推荐

  1. Chapter_4_JAVA作业

    一.类的封装,继承与多态 1.课前预习 1.1 举列现实生活中的封装,以及简述在程序中什么是属性的封装? 1.1.1 将东西捆绑在一起,如集成芯片:高压电线等等 1.1.2 封装就是将属性私有化,提供 ...

  2. docker--容器和镜像的导入导出及部署

    一.镜像导出 save 1.查看镜像 docker images 2.导出镜像 docker save -o test.tar image_name 或 docker save image_name ...

  3. CSS定位网页中的元素

    relative相对定位 偏移设置:left.right.top.bottom 值单位:px 元素的规律: 相对定位元素的规律 设置相对定位的盒子会相对它原来的位置通过指定偏移,到达新的位置. 设置相 ...

  4. shell脚本学习-练习写一个脚本2

    # 1.依次展示/var目录下的对象,并说明是文件或者目录.格式如:Hello,$file. # 2.统计一个有多少个文件. #!/bin/bash #Program Description: #Au ...

  5. ACM(数学问题)——UVa202:输入整数a和b(0≤a≤3000,1≤b≤3000),输出a/b的循环小数表示以及循环节长度。

    主要思路: 通过模拟除法运算过程,来判断循环节结束的位置,不断将余数*10再对除数取余得到新的余数,并记录下来,知道出现的余数之前出现过,此时小数开始循环. 例如: 假设   ->     a ...

  6. Java集合类的底层实现探索

    List: ArrayList 首先我们来看看jdk的ArrayList的add方法的源码是如何实现的: public boolean add(E e) { ensureCapacityInterna ...

  7. usb 枚举流程简介

    1. 枚举是什么?        枚举就是从设备读取一些信息,知道设备是什么样的设备,如何进行通信,这样主机就可以根据这些信息来加载合适的驱动程序.调试USB设备,很重要的一点就是USB的枚举过程,只 ...

  8. MySql在Mac上的安装配置

    一.下载安装 官网下载社区版dmg安装文件: https://dev.mysql.com/downloads/mysql/ 1.执行安装文件,按步骤完成安装. 2.安装完成后终端输入: mysql - ...

  9. 设置MessageBox自动关闭

    通过设置定时器,让定时器的Tick事件模拟往MessageBox发送一个Enter按钮代替用鼠标点击MessageBox上的确定按钮,来实现MessageBox的自动关闭,实现代码如下: System ...

  10. GodMode

    将“GodMode.{ED7BA470-8E54-465E-825C-99712043E01C}”(不含引号)复制过去,保存即可.