Hexo

点滴积累 豁达处之

0%

scala基础

scala基础

变量

基本语法

var 变量名 [:变量类型] = 初始值 var: Int = 10

val 常量名 [:常量类型] = 初始值 val: Int = 10

注意: 能用常量的地方不用变量

示例
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 生命变量时, 类型可以省略, 编译器自动推导,积累性推导
var a1 = 10

// 类型确定后,就不能修改,说明Scala是强数据类型语法
var a2 = 15
// a2 = "hello"
// 变量声明时,必须要有初始值
// var a3 :Int

// 在声明定义一个变量时,可以使用var或者val来修饰, var修饰的变量可以改变,val修饰的变量不可变
var a4 : Int = 10
a4 = 20

val a5 : Int = 10
// a5 = 20

命名规范

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 以字母或下划线开头,后接字母、数字、下划线
val hello: String = ""
var hello123 = ""
val _abc = 123

// var h-b = ""
// val 123abc = 123

// 以操作符开头,且只包含操作符(+ - * / # ! 等)
val -+/% = "hello"
println(-+/%)

// 用反引号 `` 包括的任意字符串, 即使是Scala关键字(39个) 也可以
val `if` = "if"
println(`if`)

字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
 // 字符串, 通过+ 号连接
val name: String = "alice"
val age: Int = 18
println(age +"岁的" + name + "在学习")

// * 用于将一个字符串复制多次拼接
println(name * 3)

// printf 用法: 字符串,通过%传值
printf("%d岁的%s在学习", age, name)

// 字符串模板(插值字符串): 通过$获取变量值
println(s"${age}岁的${name}在学习")
val num: Double = 2.3456
println(f"The num is ${num}%2.2f") // 格式化模板字符串
println(raw"The num is ${num}%2.2f")

// 三引号表示字符串,保持多行字符串的原格式输出
val sql = s"""
|select *
|from
| student
| where
| name = ${name}
| and
| age > ${age}
|""".stripMargin
println(sql)

控制台输入

1
2
3
4
5
// 输入信息
println("请输入大名:")
val name = StdIn.readLine()
println("请输入年龄:")
StdIn.readInt()

文件读写

1
2
3
4
5
6
7
8
// 从文件中读取数据
// Source.fromFile("src/main/resources/test.txt").foreach(print)

// 将数据写入文件
val write = new PrintWriter(new File("src/main/resources/output.txt"))
write.write("abcdddd")
write.write("12234444")
write.close()

数据类型

Scala_obj01

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 整数类型
val a1 : Byte = 127
// val a1 : Byte = 128 // error

val a3 = 12 // 整数默认类型为Int
val a4 = 12345678987L // 长整型数值定义

val b1: Byte = 10
val b2: Byte = (10 + 20)

val b3: Byte = (b1 + 20) // error
val b4: Byte = (b1 + 20).toByte

// 浮点类型
val f1: Float = 1.2345f
val d1 = 24.2245

// 字符类型
val c1: Char = 'a'
val c2: Char = '9'

val c3: Char = '\t' // 制表符
val c4: Char = '\n' // 换行符

// 转义字符
val c5 = '\\' // 表示\自身
val c6 = '\"' // 表示"

// 字符变量底层保存ASCII码
val i1: Int = c1
val i2: Int = c2

Unit,Null,Nothing

数据类型 描述
Unit 表示无值,和其它语言中void等同, 用作不返回任何结果的方法的结果类型,Unit只有一个实例值,写成()
Null null,Null类型只有一个实例值null
Nothing Nothing类型在Scala的类层级最低端,它是任何其它类型的子类型,当一个函数,我们确定没有正常的返回值,可以用Nothing来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)付给其它的函数或者变量(兼容性)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 空值 Unit
def m1(): Unit = {
println("m1被调用执行")
}

val a = m1()
println(a)

// 空引用 Null
// val n: Int = null // error
var student = new Student("al", 20)
student = null
println(student)

// Nothing
def m2(n: Int): Int = {
if (n == 0)
throw new NullPointerException
else
return n
}
val b = m2(0)
println(b)

运算符

1
2
3
4
5
6
7
8
9
10
val s1: String = "hello"
val s2: String = new String("hello")

println(s1 == s2) // true
println(s1.equals(s2)) // true
println(s1.eq(s2)) //false

println(1.34.*(2))
println(1.34.+(2))
println(1.34 + 2)

条件分支

1
2
3
4
5
6
7
8
9
10
11
12
13
14
val age = 4
val result = if (age < 10){
println("儿童")
}
println(result)

val age2 = 4
val result2: String = if (age2 < 10){
println("儿童")
"儿童"
}else {
"成年"
}
println(result2)

注意:条件分支的最后一行为返回值

循环

范围遍历

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
// 范围遍历
for (i <- 1 to 10) { // 前后闭合
println(i)
}
println("=========================")
for (i <- 1.to(10)) {
println(i)
}
println("=========================")
for (i <- Range(1, 10)){ // 不包含右边界
println(i)
}
println("=========================")
for (i <- 1 until 10 ){ // 不包含右边界
println(i)
}
for (i <- 10 to 1 reverse) {
println(i)
}

集合遍历

1
2
3
4
5
6
7
8
9
10
// 集合遍历
for (i <- Array(12, 34, 53) ){
println(i)
}
for (i <- List(12, 34, 53) ){
println(i)
}
for (i <- Set(12, 34, 53) ){
println(i)
}

循环守卫

1
2
3
for (i <- 1 to 10 if i != 5) {
println(i)
}

循环步长

1
2
3
4
5
6
 for (i <- 1 to 10 by 2) {
println(i)
}
for (i <- 30 to 13 by -2) {
println(i)
}

嵌套循环

1
2
3
4
5
6
7
for (i <- 1 to 3; j <- 1 to 3) { // 中间分号分割
println(i, j)
}
for (i <- 1 to 3; j <- 1 to 3 if j <= i) {
print(i, j)
if (j == i) println()
}

引入变量

1
2
3
4
5
6
7
8
9
10
11
 for (i <- 1 to 3; j = 4 - i) {
println(i, j)
}
for {
i <- 1 to 3; j = 4 - i
} {
println(i, j)
}
for (i <- 1 to 9 ; stars = 2 * i - 1; spaces = 9 - i ){ // 打印等腰三角形
println(" " * spaces + "*" * stars)
}

循环返回

1
2
3
4
5
6
7
8
// 循环返回值
val a: Unit = for (i <- 1 to 10){
i
}
println("a = " + a) // a = ()

val b = for (i <- 1 to 10) yield i
println("b = " + b) // b = Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

循环中断

scala 内置控制结构特地去掉了break和continue 是为了更好的适应函数式编程, scala中使用breakable控制结构来实现break和continue功能

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// 循环中断 (采用抛出异常方式)
try {
for (i <- 0 to 4) {
if (i == 3)
throw new RuntimeException
println(i)
}
}catch {
case e: Exception => // 什么都不做,只是退出循环
}
println("这是循环外的代码")

// 使用Scala中的breaks类的break方法, 实现异常的抛出和捕捉
Breaks.breakable(
for (i <- 0 to 4) {
if (i == 3)
Breaks.break()
println(i)
}
)
println("这是循环外的代码")

// 使用Scala中的breaks类的break方法, 实现异常的抛出和捕捉(省略Breaks)
breakable(
for (i <- 0 to 4) {
if (i == 3)
break()
println(i)
}
)
println("这是循环外的代码")

函数

函数定义

Scala_obj02

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
//定义函数
def sayHi(name: String): Unit = {
println("hi, " + name)
}
sayHi("chen")

//调用对象的方法
FuncD.sayHi("BOB")

val result = sayHello("alise")
}

//定义函数
def sayHi(name: String): Unit = {
println("Hi, " + name)
}
//定义函数
def sayHello(name: String): String = {
println("Hello, " + name)
return "Hello, " + name
}

函数参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// 可变参数
def f1(str: String*): Unit = {
println(str)
}
f1("alice") // ArraySeq(alice)
f1("a", "b") // ArraySeq(a, b)

// 如果参数列表中存在多个参数,那么可变参数一般放置在最后
def f2(str1: String, str2: String*): Unit = {
println("str1: " + str1 + " str2: " + str2)
}
f2("alice") // str1: alice str2: List()
f2("a", "b") // str1: a str2: ArraySeq(b)

// 参数默认值, 一般将有默认值的参数放置在参数列表的后面
def f3(name: String = "default"): Unit = {
println(name)
}
f3("chen") // chen
f3() // default

// 带名参数
def f4(name: String , age: Int): Unit = {
println(name, age)
}
f4("chen", 12) // (chen,12)
f4( age = 12, name = "chen") // (chen,12)

函数至简原则

函数至简原则 – 能省则省

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// return 可以省略, Scala会使用函数整体的最后一行代码作为返回值
def f0(name: String): String = {
name
}
println(f0("chen")) // chen

// 如果函数体只有一行代码, 可以省略花括号
def f1(name: String): String = name
println(f1("chen")) // chen

// 如果返回值类型能够推断出来,那么可以省略(: 和返回值类型一起省略)
def f3(name: String) = name
println(f3("chen")) // chen

// 如果有return,则不能省略返回值类型, 必须指定
def f4(name: String): String = {
return name
}
println(f4("chen")) // chen

// 如果函数明确声明Unit, 那么即使函数整体中使用return关键字也不起作用
def f5(name: String): Unit = {
return name
}
println(f5("chen")) // ()

// Scala如果期望是无返回值类型,可以省略等号
def f6(name: String) {
println(name)
}
f6("chen") // chen

// 如果函数无参,但是声明了参数列表,那么调用时,小括号可加可不加
def f7(): Unit = {
println("chen")
}
f7() // chen
f7 // chen

// 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略
def f8: Unit = {
println("chen")
}
// f8() // error
f8 // chen

// 如果不关心名称,只关心逻辑处理,那么函数名def, 可以省略
def f9(name: String): Unit = {
println(name)
}
(name: String) => { println(name) } // 匿名函数

匿名函数

1
2
3
4
5
6
7
8
val fun = (name: String) => {println(name)}
fun("chen") // chen

// 定义一个函数, 已函数作为参数
def f(func: String => Unit): Unit = {
func("chen")
}
f(fun) // chen

匿名函数简化规则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
val fun = (name: String) => {println(name)}
fun("chen") // chen

// 定义一个函数, 已函数作为参数
def f(func: String => Unit): Unit = {
func("chen")
}
f(fun) // chen

// 匿名函数的简要原则
// 参数的类型可以省略, 会根据形参进行自动推导
f((name) => {println(name)})

// 类型省略后,发现只有一个参数,则小括号可以省略, 其它情况:没有参数和参数超过1的永远不能省略小括号
f(name => {println(name)})

// 匿名函数如果只有一行, 则大括号可以省略
f(name => println(name))

// 如果参数只出现一次,则参数省略且后面参数可以用_替代
f(println(_))

// 如果可以推断出当前传入的println是一个函数体, 而不是调用语句, 可以直接省略下划线
f(println)

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 定义一个 二元运算 函数,只操作1和2两个数, 但是具体运算通过参数传入
def dualFunctionOneAndTwo(fun: (Int, Int) => Int ): Int = {
fun(1,2)
}

val add = (a: Int, b: Int) => a + b
val minus = (a: Int, b: Int) => a - b

println( dualFunctionOneAndTwo(add)) // 3
println(dualFunctionOneAndTwo(minus)) // -1

println( dualFunctionOneAndTwo((a, b) => a + b)) // 3
println( dualFunctionOneAndTwo(_ + _)) // 3
println( dualFunctionOneAndTwo(-_ + _)) // 1

高阶函数

函数作为值传递

1
2
3
4
5
6
7
8
9
10
11
12
def f(n: Int): Int = {
println("f调用")
n + 1
}
val result = f(123) // f调用
println(result) // 124

// 函数作为值进行传递
val f1 = f _
val f2: Int=>Int = f
println(f1) // chapter03.FunD05$$$Lambda$3/32863545@704a52ec
println(f1(123)) // 124

函数作为参数进行传递

1
2
3
4
5
6
7
8
// 定义一个 二元运算 函数
def dualEval(fun: (Int, Int) => Int, a: Int, b: Int ): Int = {
fun(a,b)
}

val add = (a: Int, b: Int) => a + b
val minus = (a: Int, b: Int) => a - b
println( dualEval(add, 12, 35)) // 47

函数作为返回值传递

1
2
3
4
5
6
7
8
9
10
11
def f5(): Int=>Unit = {
def f6(a: Int): Unit = {
println("f6调用 " + a)
}
f6 // 将函数直接返回
}

val f6 = f5()
println( f6) // chapter03.FunD05$$$Lambda$3/1952779858@536aaa8d
println( f6(25)) // f6调用 25
println( f5()(25)) // f6调用 25

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
def func(i: Int): String=>Char=>Boolean  = {
def f1(s: String): Char=>Boolean = {
def f2(c: Char): Boolean = {
if (i == 0 && s == "" && c == '0') false else true
}
f2
}
f1
}

// 匿名函数写法
def funcs(i: Int): String=>(Char=>Boolean) = {
s => c => if (i == 0 && s == "" && c == '0') false else true
}
// 柯里化
def func2(i: Int)(s: String)(c: Char): Boolean = {
if (i == 0 && s == "" && c == '0') false else true
}
println(func(0)("")('1')) // true

函数柯里化&闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
// 闭包 如果一个函数,访问到了它外部变量的值,那么这个函数和他所处的环境,称为闭包
def add(a: Int, b: Int): Int = {
a + b
}

def addByFour(b: Int): Int = {
4 + b
}

// 扩展固定加数改变的情况
def addByFive(b: Int): Int = {
5 + b
}

// 将固定家属作为另一个参数传入, 但是是作为"第一层参数"传入
def addByFour1(): Int=>Int = {
val a = 4
def addB(b: Int): Int = {
a + b
}
addB
}

def addByFourA(a: Int): Int=>Int = {
def addB(b: Int): Int = {
a + b
}
addB
}
println(addByFourA(35)(2)) // 37

val addByFour2 = addByFourA(4)
val addByFour3 = addByFourA(5)

println(addByFour2(13)) // 17
println(addByFour3(15)) // 20

// lambda表达式简写
def addByFourA2(a: Int): Int=>Int = a + _

// 柯里化 把一个参数列表的多个参数,变成多个参数列表
def addCurry(a: Int)(b: Int): Int = a + b
println(addCurry(5)(4)) // 9

控制抽象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
def main(args: Array[String]): Unit = {
// 1, 传值参数
def f0(a: Int): Unit = {
println("a: " + a)
println("a: " + a)
}
f0(23)
def f1(): Int = {
println("f1调用 " )
10
}
f0(f1())
println("===================================")
// 2, 传名参数
def f2(a: =>Int): Unit = {
println("a: " + a)
println("a: " + a)
}
f2(23)
f2(f1())
}

打印结果
a: 23
a: 23
f1调用
a: 10
a: 10
===================================
a: 23
a: 23
f1调用
a: 10
f1调用
a: 10

练习

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
var n = 10

// 常规while循环
while (n >= 1){
println(n)
n -= 1
}

// 闭包实现
def myWhile(condition: =>Boolean): (=>Unit)=>Unit = {
// 内层函数,需要递归调用,参数就是循环体
def doLoop(op: =>Unit): Unit = {
if (condition){
op
myWhile(condition)(op)
}
}
doLoop _
}
n = 10
myWhile(n >= 1){
println(n)
n -= 1
}

// 匿名函数实现
def myWhile2(condition: =>Boolean): (=>Unit)=>Unit = {
// 内层函数,需要递归调用,参数就是循环体
op => {
if (condition){
op
myWhile2(condition)(op)
}
}
}

// 柯里化实现
def myWhile3(condition: =>Boolean)(op: =>Unit): Unit = {
if (condition){
op
myWhile2(condition)(op)
}
}

惰性加载

说明:当函数返回值被声明为lazy时,函数的执行将被推迟,知道我们首次对此取值,该函数才会执行,这种函数我们称为惰性函数

1
2
3
4
5
6
7
def sum(a: Int, b: Int): Int ={
println("sum调用")
a + b
}
lazy val result = sum(13, 17)
println("函数调用")
println("result = " + result)

面向对象

包说明

包说明: 包可以嵌套

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package chapter03{
import chapter03.FunD06.Inner
// 外层包中定义单例对象
object Outer {
var out: String = "out"
def main(args: Array[String]): Unit = {
println(Inner.inner) // inner
Inner.inner = "inner02"
println(Inner.inner) // inner02
}
}
package FunD06{
// 内层包中定义单例对象
object Inner {
var inner: String = "inner"
def main(args: Array[String]): Unit = {
println(Outer.out) // out
Outer.out = "outer02"
println(Outer.out) // outer02
}
}
}
}

包对象

在scala中可以为每个包定义一个同名的包对象,定义在包对象中的成员,作为其对应包下所有class和object的共享变量,可以被直接访问

1
2
3
4
5
6
7
8
9
10
11
package object FunD06 {
// 定义当前包共享的属性和方法
val commonValue = "jiumao"
def commonMethod() = {
println(s"${commonValue} say hello")
}
}

def main(args: Array[String]): Unit = {
commonMethod() // jiumao say hello
}

构造器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
// 定义一个类
class Student1 {
// 定义属性
var name: String = "chen"
var age: Int = _
var sex: String = _

println("a, 主构造方法被调用")

// 辅助构造方法
def this(name: String){
this() // 直接调用构造器
println("b, 辅助构造方法一被调用")
this.name = name
println(s"name:$name age: $age")
}

// 辅助构造方法
def this(name: String, age: Int){
this(name) // 直接调用构造器
println("c, 辅助构造方法二被调用")
this.age = age
println(s" name:$name age: $age")
}

def Student1(): Unit = {
println("一般方法被调用")
}
}

def main(args: Array[String]): Unit = {
val student1 = new Student1 // a, 主构造方法被调用
student1.Student1() // 一般方法被调用
val student2 = new Student1("chen")
val student3 = new Student1("chen02", 10)
}

打印结果
a, 主构造方法被调用
一般方法被调用
a, 主构造方法被调用
b, 辅助构造方法一被调用
name:chen age: 0
a, 主构造方法被调用
b, 辅助构造方法一被调用
name:chen02 age: 0
c, 辅助构造方法二被调用
name:chen02 age: 10

构造器参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 定义类
// 无参构造方法
class Student2 {
// 单独定义属性
var name: String = "chen"
var age: Int = _
}
// 上面定义等价于
class Student3(var name: String, var age: Int)
// val 声明
class Student5(val name: String, val age: Int)
// 主构造器参数无修饰
class Student4( name: String, age: Int)

val student2 = new Student2
student2.name = "chen"
student2.age = 12
println(s"student2: name: ${student2.name} age: ${student2.age}") // student2: name: chen age: 12

val student3 = new Student3("chen", 12)
println(s"student3: name: ${student3.name} age: ${student3.age}") // student2: name: chen age: 12

val student4 = new Student4("chen", 12)
// println(s"student3: name: ${student4.name} age: ${student4.age}") // error

val student5 = new Student5("chen", 12)
// student5.age = 30 // error
println(s"student5: name: ${student5.name} age: ${student5.age}") // student2: name: chen age: 12

继承

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
// 定义一个父类
class Person7(){
var name: String = _
var age: Int = _
println("1 父类的主构造器调用")

def this(name: String, age: Int){
this()
println("2 父类的辅助构造器被调用")
this.name = name
this.age = age
}

def printInfo(): Unit = {
println(s"Person: $name, $age" )
}
}

// 定义子类
class Student7(name: String, age: Int) extends Person7 {
var stuNo: String = _

println("3 子类的主构造器调用")

def this(name: String, age: Int, stuNo: String){
this(name,age )
println("4 子类的辅助构造器被调用")
this.stuNo = stuNo
}

override def printInfo(): Unit = {
println(s"Student: $name, $age" )
}
}

def main(args: Array[String]): Unit = {
val student1 = new Student7("chen",12)
val student2 = new Student7("chen3",13, "stu001")
}

打印结果
1 父类的主构造器调用
3 子类的主构造器调用
1 父类的主构造器调用
3 子类的主构造器调用
4 子类的辅助构造器被调用

多态

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
object ObjDuo01 {
def main(args: Array[String]): Unit = {
val person: Person = new Worker
println(person.name)
person.sayHello()
}
}

class Person {
var name: String = "person"
def sayHello() = {
println("hello perosn")
}
}

class Worker extends Person {
override var name: String = "worker"
override def sayHello() = {
println("hello worker")
}
}

单例对象(伴生对象)

Scala语言是完全面向对象的语言,所以并没有静态的操作(即在Scala中没有静态的概念)。 但是为了能够和Java语言交互(因为Java中有静态概念),就产生了一种特殊的对象来模拟类对象,该对象为单例对象,若单例对象名与类名一致,则称该单例对象这个类的伴生对象,这个类的所有”静态“内容都可以放置在它的伴生对象中声明

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
object Obj11 {
def main(args: Array[String]): Unit = {
val student1 = Student11.newStudent("chen", 12)
student1.printInfo()
}
}

// 定义类
class Student11 private (val name: String, val age: Int){
def printInfo(): Unit ={
println(s"student name = $name age = $age school = ${Student11.school}")
}
}

// 伴生对象
object Student11{
val school: String = "xue"

// 定义一个类的对象的创建方法
def newStudent(name: String, age: Int): Student11 = {
new Student11(name, age)
}
}

apply 方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
object Obj11 {
def main(args: Array[String]): Unit = {
val student2 = Student11.apply("chen", 12)
val student3 = Student11("chen", 12)
student1.printInfo()
student2.printInfo()
}
}

// 定义类
class Student11 private (val name: String, val age: Int){
def printInfo(): Unit ={
println(s"student name = $name age = $age school = ${Student11.school}")
}
}

// 伴生对象
object Student11{
val school: String = "xue"

def apply(name: String, age: Int): Student11 = {
new Student11(name, age)
}
}

特质

Scala 语言中, 采用trait(特质)来替代接口的概念, 也就是说, 多个类具有相同的特质时,就可以将这个特质独立出来,采用关键字trait声明

Scala中的trait中既可以有抽象属性和方法,也可以有具体的属性和方法,一个类可以混入多个特质,这种感觉类似于Java中的抽象类

Scala引入trait特质,第一可以替代Java的接口,第二也是对单例继承的一种补充

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
object Obj_trait13 {
def main(args: Array[String]): Unit = {
val student1 = new Student13
student1.sayHello()
}

// 打印结果
// hello from: student
// student hello from: student
}

// 父类
class Person13 {
val name: String = "person"
var age: Int = 18
def sayHello(): Unit = {
println("hello from: " + name)
}
}

// 定义特质
trait Young {
// 声明抽象和非抽象属性
var age:Int
val name: String = "yount"

// 声明抽象和非抽象方法
def play(): Unit = {
println("young perple is playing")
}
def dating(): Unit
}

class Student13 extends Person13 with Young {
// 重写冲突的属性
override val name: String = "student"
// 实现抽象方法
def dating(): Unit = println(s"student $name dating")

//
def study(): Unit = println(s"student $name is studying")

override def sayHello()= {
super.sayHello()
println("student hello from: " + name)
}
}

动态混入

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
object Obj_trait13 {
def main(args: Array[String]): Unit = {

val student2 = new Student13 with Talent {
override def dancing(): Unit = {

}

override def singing(): Unit = {

}
}
}
}

trait Talent {
def singing(): Unit
def dancing(): Unit
}

特征叠加

特征重复时,以最后一个特征为准

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
object Obj_trait15 {
def main(args: Array[String]): Unit = {
val student1 = new Student15
student1.increase() // talent increased
}
}

trait Knowledge15 {
var amount: Int = 0
def increase(): Unit = {
println("knowledge increased")
}
}

trait Talent15 {
def singing(): Unit
def dancing(): Unit
def increase(): Unit = {
println("talent increased")
}
}


class Student15 extends Person13 with Knowledge15 with Talent15 {
override def singing(): Unit = println("singing")

override def dancing(): Unit = println("dancing")

override def increase(): Unit = {
super.increase()
}
}

特征叠加的执行顺序

Scala_obj03

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
object Obj_trait15 {
def main(args: Array[String]): Unit = {
val myFootBall = new MyFootBall
println(myFootBall.describe()) // my ball is red-foot-ball
}
}

trait Ball {
def describe(): String = "ball"
}

//定义颜色特征
trait ColorBall extends Ball {
var color: String = "red"
override def describe(): String = color + "-" + super.describe()
}

// 定义种类特征
trait CategoryBall extends Ball {
var category: String = "foot"
override def describe(): String = category + "-" + super.describe()
}

//
class MyFootBall extends CategoryBall with ColorBall {
override def describe(): String = "my ball is " + super.describe()
}

指定特征

1
super[CategoryBall].describe()  // super后指定特征

自身类型

1
_: 特质/类名称 =>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
object Obj_trait16 {
def main(args: Array[String]): Unit = {
val registerUser = new RegisterUser("chen", "chen")
registerUser.insert()
}
}

// 用户类
class User(val name: String, val password: String)

//
trait UserDao {
_: User =>

//. 插入
def insert(): Unit = {
println(s"insert into db: ${this.name}" )
}
}

// 定义注册用户类
class RegisterUser(name: String, password: String) extends User(name, password ) with UserDao

扩展

类型检查和转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
object Obj_extend17 {
def main(args: Array[String]): Unit = {
// 类型的检测和转换
val student1 = new Student17("chen", 18)
student1.study() // student study
student1.sayHello() // hi form student chen
val person: Person17 = new Student17("chen", 18)
person.sayHello() // hi form student chen

// 类型判断
println("student is student17: " + student1.isInstanceOf[Student17]) // student is student17: true
println("student is person17: " + student1.isInstanceOf[Person17]) // student is person17: true
println("person is person17: " + person.isInstanceOf[Person17]) //person is person17: true
println("person is student17: " + person.isInstanceOf[Student17]) // person is student17: true
val person2: Person17 = new Person17("chen", 18)
println("person2 is person17: " + person2.isInstanceOf[Person17]) //person2 is person17: true
println("person2 is student17: " + person2.isInstanceOf[Student17]) // person2 is student17: false

// 类型转换
if (person.isInstanceOf[Student17]) {
val newStudent = person.asInstanceOf[Student17]
newStudent.study() // student study
}

println(classOf[Student17]) // class chapter07.Student17
}
}

class Person17(val name: String, val age: Int){
def sayHello(): Unit = {
println("hi form person " + name )
}
}


class Student17( name: String, age: Int) extends Person17 (name, age){
override def sayHello(): Unit = {
println("hi form student " + name )
}

def study(): Unit = {
println("student study")
}
}

枚举类和应用类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
object Obj_extend19 {
def main(args: Array[String]): Unit = {
println(WorkDay.MONDAY)
}
}

object WorkDay extends Enumeration {
val MONDAY = Value(1, "MonDay")
val TUESDAY = Value(2, "TuesDay")
}

// 定义应用类
object TestApp extends App {
println("app start")
}

Type 定义新类型

1
2
type MyString = String 
val a: MyString = "abc"