Scala 详细笔记(尚硅谷版)

字符串输出

规则

(1) 字符串,通过+号连接

(2) printf 用法:字符串,通过%传值。

(3) 字符串模板(插值字符串):通过$获取变量值

案例实操

def main(args: Array[String]): Unit = {

var name: String = "jinlian" 
var age: Int = 18

//(1)字符串,通过+号连接
println(name + " " + age)

//(2)printf 用法字符串,通过%传值。
printf("name=%s age=%d\n", name, age)

//(3)字符串,通过$引用
//多行字符串,在Scala 中,利用三个双引号包围多行字符串就可以实现。
//输入的内容,带有空格、\t 之类,导致每一行的开始位置不能整洁对齐。
//应用 scala 的 stripMargin 方法,在 scala 中 stripMargin 默认是“|”作为连接符,
//在多行换行的行头前面加一个“|”符号即可。
val s =
"""
|select
|	name,
|	age
|from user
|where name="zhangsan" 
""".stripMargin
println(s)

//如果需要对变量进行运算,那么可以加${} 
val s1 =
s"""
|select
|	name,
|	age
|from user
|where name="$name" and age=${age+2} """.stripMargin
println(s1)

val s2 = s"name=$name" 
println(s2)
}


数据类型(重点)

Java数据类型

Java基本类型:char、byte、short、int、long、float、double、boolean

Java引用类型:(对象类型)

由于Java有基本类型,而且基本类型不是真正意义的对象,即使后面产生了基本类型的包装类,但是仍 然存在基本数据类型,所以Java语言并不是真正意思的面向对象。

Java基本类型的包装类:Character、Byte、Short、Integer、Long、Float、Double、Boolean

注意:Java中基本类型和引用类型没有共同的祖先。

Scala数据类型

1) Scala中一切数据都是对象,都是Any的子类。

2) Scala中数据类型分为两大类:数值类型(AnyVal)、 引用类型(AnyRef),不管是值类型还是引用类型都是对象。

3) Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)

4) Scala中的StringOps是对Java中的String增强

5) Unit:对应Java中的void,用于方法返回值的位置,表 示方法没有返回值。Unit是一个数据类型,只有一个对象 就是()。Void不是数据类型,只是一个关键字

6) Null是一个类型,只有一个对象就是null。它是所有引用类型(AnyRef)的子类。

7) Nothing,是所有数据类型(应用类型和数值类型)的子类,主要用在一个函数没有明确返回值时使 用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。

在这里插入图片描述

整数类型

数据类型描述
Byte [1]8 位有符号补码整数。数值区间为 -128 到 127
Short [2]16 位有符号补码整数。数值区间为 -32768 到 32767
Int [4]32 位有符号补码整数。数值区间为 -2147483648 到 2147483647
Long [8]64 位有符号补码整数。数值区间为 -9223372036854775808 到 9223372036854775807 = 2 的(64-1)次方-1

Unit 类型、Null 类型和Nothing 类型(重点)

基本说明
数据类型描述
Unit表示无值,和其他语言中 void 等同。用作不返回任何结果的方法的结果 类型。Unit 只有一个实例值,写成()。
Nullnull , Null 类型只有一个实例值 null
NothingNothing 类型在 Scala 的类层级最低端;它是任何其他类型的子类型。当一个函数,我们确定没有正常的返回值,可以用 Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回的值(异常)赋给其它的函数 或者变量(兼容性)
案例实操
  • Unit 类型用来标识过程,也就是没有明确返回值的函数。由此可见,Unit 类似于 Java 里的void。Unit 只有一个实例——( ),这个实例也没有实质意义
object TestSpecialType {

def main(args: Array[String]): Unit = {

def sayOk : Unit = {// unit 表示没有返回值,即 void
}
println(sayOk)
}
}
  • Null 类只有一个实例对象,Null 类似于 Java 中的 null 引用。Null **可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(**AnyVal)
object TestDataType {

def main(args: Array[String]): Unit = {
//null 可以赋值给任意引用类型(AnyRef),但是不能赋值给值类型(AnyVal)
var cat = new Cat(); cat = null	// 正 确
var n1: Int = null // 错 误
println("n1:" + n1)
}
}
class Cat {
}
  • Nothing,可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,而且由于 Nothing 是其他任意类型的子类,他还能跟要求返回值的方法兼容。
object TestSpecialType {
def main(args: Array[String]): Unit = { 
def test() : Nothing={
throw new Exception()
}
test
}
}

数值类型自动转换

当Scala 程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为:

在这里插入图片描述

基本说明

(1) 自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数据类型,然后再进行计算。

(2) 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。

(3)(byte,short)和 char 之间不会相互自动转换。

(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int 类型。

案例实操
object TestValueTransfer {
def main(args: Array[String]): Unit = {

//(1)自动提升原则:有多种类型的数据混合运算时,系统首先自动将所有数据转换成精度大的那种数值类型,然后再进行计算。
var n = 1 + 2.0
println(n)	// n 就 是 Double
//(2)把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
var n2 : Double= 1.0
//var n3 : Int = n2 //错误,原因不能把高精度的数据直接赋值和低
精度。
//(3)(byte,short)和 char 之间不会相互自动转换。
var n4 : Byte = 1
//var c1 : Char = n4	//错误var n5:Int = n4

//(4)byte,short,char 他们三者可以计算,在计算时首先转换为 int类型。
var n6 : Byte = 1 
var c2 : Char = 1
// var n : Short = n6 + c2 //当 n6 + c2 结果类型就是int
// var n7 : Short = 10 + 90 //错误
}
}

关系运算符

Java 和Scala 中关于==的区别

Java

==比较两个变量本身的值,即两个对象在内存中的首地址;

equals 比较字符串中所包含的内容是否相同。

public static void main(String[] args) {

String s1 = "abc";
String s2 = new String("abc"); System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
}
输出结果:
false
true
Scala

==更加类似于 Java 中的 equals,参照 jd 工具

def main(args: Array[String]): Unit = { 
val s1 = "abc"
val s2 = new String("abc")

println(s1 == s2) 
println(s1.eq(s2))
}
输出结果:
true
false

注意:Scala 中没有++、–操作符,可以通过+=、-=来实现同样的效果;

Scala 运算符本质

在 Scala 中其实是没有运算符的,所有运算符都是方法。

1) 当调用对象的方法时,点.可以省略

2) 如果函数参数只有一个,或者没有参数,()可以省略

object TestOpt {
def main(args: Array[String]): Unit = {

// 标准的加法运算
val i:Int = 1.+(1)

// (1)当调用对象的方法时,.可以省略
val j:Int = 1 + (1)

// (2)如果函数参数只有一个,或者没有参数,()可以省略
val k:Int = 1 + 1

println(1.toString()) 
println(1 toString()) 
println(1 toString)
}
}

流程控制

IF流程

与Java类似

For 循环控制

Scala 也为 for 循环这一常见的控制结构提供了非常多的特性,这些 for 循环的特性被称为 for 推导式或 for 表达式。

范围数据循环(To)
基本语法
for(i <- 1 to 3){
print(i + " ")
}
println()
说明

(1) i 表示循环的变量,<- 规定 to

(2) i 将会从 1-3 循环,前后闭合

范围数据循环(Until)
基本语法
for(i <- 1 until 3) { print(i + " ")
}
println()
说明

(1) 这种方式和前面的区别在于 i 是从 1 到 3-1

(2) 即使前闭合后开的范围

循环守卫
基本语法
for(i <- 1 to 3 if i != 2) { 
    print(i + " ")
}
println()
说明

(1) 循环守卫,即循环保护式(也称条件判断式,守卫)。保护式为 true 则进入循环体内部,为false 则跳过,类似于continue。

(2) 上面的代码等价于

for (i <- 1 to 3){
	if (i != 2) {
		print(i + " ")
		}
}

循环步长
基本语法
for (i <- 1 to 10 by 2) { 
	println("i=" + i)
}

说明

by 表示步长

案例实操

需求:输出 1 到 10 以内的所有奇数

for (i <- 1 to 10 by 2) { 
	println("i=" + i)
}

输出结果

i=1 
i=3 
i=5 
i=7
i=9
嵌套循环
基本语法
for(i <- 1 to 3; j <- 1 to 3) { 
	println(" i =" + i + " j = " + j)
}
说明

没有关键字,所以范围后一定要加;来隔断逻辑

上面的代码等价

for (i <- 1 to 3) {
	for (j <- 1 to 3) {
		println("i =" + i + " j=" + j)
	}
}

引入变量
基本语法
for(i <- 1 to 3; j = 4 - i) { 
	println("i=" + i + " j=" + j)
}
说明

(1) for 推导式一行中有多个表达式时,所以要加 ; 来隔断逻辑

(2) for 推导式有一个不成文的约定:当 for 推导式仅包含单一表达式时使用圆括号, 当包含多个表达式时,一般每行一个表达式,并用花括号代替圆括号,如下

for {
	i <- 1 to 3 
	j = 4 - i
} {
println("i=" + i + " j=" + j)
}
循环返回值
基本语法
val res = for(i <- 1 to 10) yield i
println(res)
说明

将遍历过程中处理的结果返回到一个新 Vector 集合中,使用 yield 关键字。

案例实操

需求:将原数据中所有值乘以 2,并把数据返回到一个新的集合中。

object TestFor {
def main(args: Array[String]): Unit = { 
    var res = for(i <-1 to 10) yield 
   {
	i * 2
	}
println(res)
}
}
输出结果:
Vector(2, 4, 6, 8, 10, 12, 14, 16, 18, 20)
倒序打印
说明

如果想倒序打印一组数据,可以用 reverse。

案例实操

需求:倒序打印 10 到 1

for(i <- 1 to 10 reverse){ 
	println(i)
}

While 和 do…While 循环控制

While 和 do…While 的使用和 Java 语言中用法相同。

循环中断

基本说明

Scala 内置控制结构特地去掉了 break 和 continue,是为了更好的适应函数式编程,推荐使用函数式的风格解决break 和continue 的功能,而不是一个关键字。Scala 中使用breakable 控制结构来实现 break 和 continue 功能。

案例实操

需求 1:采用异常的方式退出循环

def main(args: Array[String]): Unit = {

try {
for (elem <- 1 to 10) { println(elem)
if (elem == 5) throw new RuntimeException
}
}catch {
case e =>
}
println("正常结束循环")
}

需求 2:采用 Scala 自带的函数,退出循环

import scala.util.control.Breaks
def main(args: Array[String]): Unit = { 
    Breaks.breakable(
		for (elem <- 1 to 10) { println(elem)
		if (elem == 5) Breaks.break()
	}
)
println("正常结束循环")
}

需求 3:对break 进行省略

import scala.util.control.Breaks._ object TestBreak {
def main(args: Array[String]): Unit = {

	breakable {
		for (elem <- 1 to 10) { 
            println(elem)
		if (elem == 5) break
	}
}

println("正常结束循环")
	}
}

需求 4:循环遍历 10 以内的所有数据,奇数打印,偶数跳过(continue)

object TestBreak {
def main(args: Array[String]): Unit = { 
    for (elem <- 1 to 10) {
		if (elem % 2 == 1) { 
            println(elem)
		} else {
			println("continue")
			}
		}
	}
}

函数式编程

1) 面向对象编程

对象:用户

行为:登录、连接 JDBC、读取数据库属性:用户名、密码

Scala 语言是一个完全面向对象编程语言。万物皆对象

对象的本质:对数据和行为的一个封装

2) 函数式编程

解决问题时,将问题分解成一个一个的步骤,将每个步骤进行封装(函数),通过调用这些封装好的步骤,解决问题。

例如:请求->用户名、密码->连接 JDBC->读取数据库

Scala 语言是一个完全函数式编程语言。万物皆函数。

函数的本质:函数可以当做一个值进行传递

3) 在Scala 中函数式编程和面向对象编程完美融合在一起了。

函数基础

函数基本语法

在这里插入图片描述

案例实操

需求:定义一个函数,实现将传入的名称打印出来。

object TestFunction {

def main(args: Array[String]): Unit = {

// (1)函数定义
def f(arg: String): Unit = {
	println(arg)
}
// (2)函数调用
// 函数名(参数)
	f("hello world")
	}
}

函数和方法的区别

核心概念

(1) 为完成某一功能的程序语句的集合,称为函数。

(2) 类中的函数称之方法。

案例实操

(1) Scala 语言可以在任何的语法结构中声明任何的语法

(2) 函数没有重载和重写的概念;方法可以进行重载和重写

(3) Scala 中函数可以嵌套定义

object TestFunction {
// (2)方法可以进行重载和重写,程序可以执行
    def main(): Unit = {
}
def main(args: Array[String]): Unit = {
// (1)Scala 语言可以在任何的语法结构中声明任何的语法
	import java.util.Date 
    new Date()
// (2)函数没有重载和重写的概念,程序报错
    def test(): Unit ={
		println("无参,无返回值")
	}
	test()
	def test(name:String):Unit={ println()
	}
//(3)Scala 中函数可以嵌套定义
	def test2(): Unit ={
	println("函数可以嵌套定义")
				}
			}
		}
	}

函数参数

案例实操

(1) 可变参数

(2) 如果参数列表中存在多个参数,那么可变参数一般放置在最后(def test( s : String* )😃

(3) 参数默认值,一般将有默认值的参数放置在参数列表的后面

(4) 带名参数

object TestFunction {

def main(args: Array[String]): Unit = {

// (1)可变参数
def test( s : String* ): Unit = { println(s)
}

// 有输入参数:输出 Array test("Hello", "Scala")

// 无输入参数:输出List() test()

// (2)如果参数列表中存在多个参数,那么可变参数一般放置在最后
def test2( name : String, s: String* ): Unit = {
println(name + "," + s)
}

test2("jinlian", "dalang")

// (3)参数默认值
def test3( name : String, age : Int = 30 ): Unit = {
 println(s"$name, $age")
}

// 如果参数传递了值,那么会覆盖默认值
test3("jinlian", 20)

// 如果参数有默认值,在调用的时候,可以省略这个参数
test3("dalang")

// 一般情况下,将有默认值的参数放置在参数列表的后面
def test4( sex : String = "男", name : String ): Unit =	{ println(s"$name, $sex")
}
// Scala 函数中参数传递是,从左到右
//test4("wusong")

//(4)带名参数test4(name="ximenqing")
}

函数至简原则(重点)

至简原则细节

(1) return 可以省略,Scala 会使用函数体的最后一行代码作为返回值

(2) 如果函数体只有一行代码,可以省略花括号

(3) 返回值类型如果能够推断出来,那么可以省略(:和返回值类型一起省略)

(4) 如果有 return,则不能省略返回值类型,必须指定

(5) 如果函数明确声明unit,那么即使函数体中使用 return 关键字也不起作用

(6) Scala 如果期望是无返回值类型可以省略等号

(7) 如果函数无参,但是声明了参数列表,那么调用时,小括号,可加可不加

(8) 如果函数没有参数列表,那么小括号可以省略,调用时小括号必须省略

(9) 如果不关心名称,只关心逻辑处理,那么函数名(def)可以省略

案例实操
object TestFunction {

def main(args: Array[String]): Unit = {

// (0)函数标准写法
def f( s : String ): String = { 
    return s + " jinlian"
}
println(f("Hello"))

// 至简原则:能省则省
//(1) return 可以省略,Scala 会使用函数体的最后一行代码作为返回值
def f1( s : String ): String =	{ 
    s + " jinlian"
}
println(f1("Hello"))

//(2)如果函数体只有一行代码,可以省略花括号
    def f2(s:String):String = s + " jinlian"

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

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

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

//(6)Scala 如果期望是无返回值类型,可以省略等号
// 将无返回值的函数称之为过程
def f6() {
"dalang6"
}
println(f6())

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

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

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

	def f10(f:String=>Unit) = { 
        f("")
}

f10(f9)
println(f10((x:String)=>{println("wusong")}))
}
}

函数高级

高阶函数
object TestFunction {

def main(args: Array[String]): Unit = {
// 调用函数
foo()
}
// 定义函数
def foo():Unit = { println("foo...")
}

函数可以作为值进行传递
object TestFunction {

def main(args: Array[String]): Unit = {

//(1)调用 foo 函数,把返回值给变量f
//val f = foo() 
val f = foo 
println(f)
传递给变量 f1
val f1 = foo _

//(3)如果明确变量类型,那么不使用下划线也可以将函数作为整体传递给
变量
var f2:()=>Int = foo
}

def foo():Int = { println("foo...") 1
}

函数可以作为参数进行传递
def main(args: Array[String]): Unit = {

//(1)定义一个函数,函数参数还是一个函数签名;f 表示函数名称;(Int,Int)表示输入两个 Int 参数;Int 表示函数返回值
def f1(f: (Int, Int) => Int): Int = { 
	f(2, 4)
}

// (2)定义一个函数,参数和返回值类型和f1 的输入参数一致
def add(a: Int, b: Int): Int = a + b

// (3)将 add 函数作为参数传递给 f1 函数,如果能够推断出来不是调用,_ 可以省略
println(f1(add)) println(f1(add _))
//可以传递匿名函数
}

函数可以作为函数返回值返回
def main(args: Array[String]): Unit = { 
	def f1() = {
		def f2() = {
		}
		f2 _
}

val f = f1()
// 因为f1 函数的返回值依然为函数,所以可以变量f 可以作为函数继续调用
f()
// 上面的代码可以简化为
f1()()

匿名函数
说明

没有名字的函数就是匿名函数。

(x:Int)=>{函数体}

x:表示输入参数类型;Int:表示输入参数类型;函数体:表示具体代码逻辑

案例实操

需求 1:传递的函数有一个参数

传递匿名函数至简原则:

(1) 参数的类型可以省略,会根据形参进行自动的推导

(2) 类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过 1 的永远不能省略圆括号。

(3) 匿名函数如果只有一行,则大括号也可以省略

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

def main(args: Array[String]): Unit = {

// (1)定义一个函数:参数包含数据和逻辑函数
def operation(arr: Array[Int], op: Int => Int) = { 
    for (elem <- arr) yield op(elem)
}

// (2)定义逻辑函数
def op(ele: Int): Int = { 
    ele + 1
}

// (3)标准函数调用
val arr = operation(Array(1, 2, 3, 4), op) 
println(arr.mkString(","))

// (4)采用匿名函数
val arr1 = operation(Array(1, 2, 3, 4), (ele: Int) => { ele + 1})
    
// (4.1)参数的类型可以省略,会根据形参进行自动的推导; 
val arr2 = operation(Array(1, 2, 3, 4), (ele) => {ele + 1})
println(arr2.mkString(","))

// (4.2)类型省略之后,发现只有一个参数,则圆括号可以省略;其他情况:没有参数和参数超过 1 的永远不能省略圆括号。
val arr3 = operation(Array(1, 2, 3, 4), ele => { ele + 1 })
println(arr3.mkString(","))

// (4.3) 匿名函数如果只有一行,则大括号也可以省略
val arr4 = operation(Array(1, 2, 3, 4), ele => ele + 1) println(arr4.mkString(","))

//(4.4)如果参数只出现一次,则参数省略且后面参数可以用_代替
val arr5 = operation(Array(1, 2, 3, 4), _ + 1) println(arr5.mkString(","))
}


object TestFunction {

def main(args: Array[String]): Unit = {

def calculator(a: Int, b: Int, op: (Int, Int) => Int): Int
= {
op(a, b)
}

// (1)标准版
println(calculator(2, 3, (x: Int, y: Int) =>	{x + y}))

// (2)如果只有一行,则大括号也可以省略
println(calculator(2, 3, (x: Int, y: Int) =>	x + y))

// (3)参数的类型可以省略,会根据形参进行自动的推导; 
println(calculator(2, 3, (x , y) =>	x + y))

// (4)如果参数只出现一次,则参数省略且后面参数可以用_代替
println(calculator(2, 3,	_ + _))
}
}

函数柯里化&闭包

闭包:函数式编程的标配

说明

闭包:如果一个函数,访问到了它的外部(局部)变量的值,那么这个函数和他所处的环境,称为闭包

函数柯里化:把一个参数列表的多个参数,变成多个参数列表。

案例实操
object TestFunction {

def main(args: Array[String]): Unit = { 
    def f1()={
		var a:Int = 10 
        def f2(b:Int)={
			a + b
		}
		f2 _
}

// 在调用时,f1 函数执行完毕后,局部变量a 应该随着栈空间释放掉
val f = f1()

// 但是在此处,变量a 其实并没有释放,而是包含在了 f2 函数的内部,形成了闭合的效果
println(f(3))

println(f1()(3))
// 函数柯里化,其实就是将复杂的参数逻辑变得简单化,函数柯里化一定存在闭包
def f3()(b:Int)={ 
    a + b
}

println(f3()(3))
}

控制抽象
值调用:把计算后的值传递过去

与java类似

名调用:把代码传递过去
object TestControl {
def main(args: Array[String]): Unit = { def f = ()=>{
println("f...")
10
}

foo(f())
}

//def foo(a: Int):Unit = {
def foo(a: =>Int):Unit = {//注意这里变量 a 没有小括号了
println(a) println(a)
}
}
输出结果:
f... 10 f...
10

注意:Java 只有值调用;Scala 既有值调用,又有名调用。

案例实操

object TestFunction {

def main(args: Array[String]): Unit = {

// (1)传递代码块
foo({
println("aaa")
})

// (2)小括号可以省略
foo{
println("aaa")
}
}

def foo(a: =>Unit):Unit = { println(a)
println(a)
}
}

惰性加载
说明

函数返回值被声明为 lazy ,函数的执行将被推迟,直到我们首次对此取值,该函数才会执行。这种函数我们称之为惰性函数。

案例实操
def main(args: Array[String]): Unit = {

lazy val res = sum(10, 30) 
println("	")
println("res=" + res)
}

def sum(n1: Int, n2: Int): Int = {
println("sum 被执行。。。") return n1 + n2
}

输出结果

----------------
sum 被执行。。。
res=40	

注意:lazy 不能修饰 var 类型的变量

面向对象

Scala 的面向对象思想和 Java 的面向对象思想和概念是一致的。

Scala 中语法和 Java 不同,补充了更多的功能。

Scala 包

Scala 包的三大作用(和 Java 一样)

(1) 区分相同名字的类

(2) 当类很多时,可以很好的管理类

(3) 控制访问范围

类和对象

定义类
回顾

Java 中的类

如果类是 public 的,则必须和文件名一致。一般,一个.java 有一个 public 类

注意:Scala 中没有 public,一个.scala 中可以写多个类。

基本语法

[修饰符] class 类名 {

​ 类体

}

属性
基本语法

[修饰符] var|val 属性名称 [:类型] = 属性值

**注:**Bean 属性(@BeanPropetry),可以自动生成规范的 setXxx/getXxx 方法

案例实操
package com.atguigu.scala.test import scala.beans.BeanProperty class Person {
var name: String = "bobo" //定义属性
var age: Int = _ // _表示给属性一个默认值
//Bean 属性(@BeanProperty)
@BeanProperty var sex: String = "男"
//val 修饰的属性不能赋默认值,必须显示指定
}

object Person {
def main(args: Array[String]): Unit = {

var person = new Person() 
println(person.name)

person.setSex(" 女 ") 
println(person.getSex)
}
}

封装

封装就是把抽象出的数据和对数据的操作封装在一起,数据被保护在内部,程序的其它部分只有通过被授权的操作(成员方法),才能对数据进行操作。Java 封装操作如下,

(1) 将属性进行私有化

(2) 提供一个公共的 set 方法,用于对属性赋值

(3) 提供一个公共的 get 方法,用于获取属性的值

Scala 中的 public 属性,底层实际为 private,并通过 get 方法(obj.field())和 set 方法(obj.field_=(value))对其进行操作。所以 Scala 并不推荐将属性设为 private,再为其设置public 的 get 和 set 方法的做法。但由于很多 Java 框架都利用反射调用 getXXX 和 setXXX 方法,有时候为了和这些框架兼容,也会为 Scala 的属性设置 getXXX 和 setXXX 方法(通过@BeanProperty 注解实现)。

访问权限

说明

在 Java 中,访问权限分为:public,private,protected 和默认。在 Scala 中,你可以通过类似的修饰符达到同样的效果。但是使用上有区别。

(1) Scala 中属性和方法的默认访问权限为 public,但 Scala 中无 public 关键字。

(2) private 为私有权限,只在类的内部和伴生对象中可用。

(3) protected 为受保护权限,Scala 中受保护权限比 Java 中更严格,同类、子类可以访问,同包无法访问。

(4) private[包名]增加包访问权限,包名下的其他类也可以使用

案例实操

方法

创建对象

基本语法

val | var 对象名 [:类型] = new 类型()

案例实操

(1) val 修饰对象,不能改变对象的引用(即:内存地址),可以改变对象属性的值。

(2) var 修饰对象,可以修改对象的引用和修改对象的属性值

(3) 自动推导变量类型不能多态,所以多态需要显示声明

构造器

和 Java 一样,Scala 构造对象也需要调用构造方法,并且可以有任意多个构造方法。

Scala 类的构造器包括:主构造器和辅助构造器

基本语法
class  类名(形参列表) {	// 主构造器
// 类 体
def	this(形参列表) {	// 辅助构造器
}

def	this(形参列表) {	//辅助构造器可以有多个...
}

}

说明

(1) 辅助构造器,函数的名称 this,可以有多个,编译器通过参数的个数及类型来区分。

(2) 辅助构造方法不能直接构建对象,必须直接或者间接调用主构造方法。

(3) 构造器调用其他另外的构造器,要求被调用构造器必须提前声明(及上述基本语法中的第一个this不能调第二个this)。

案例实操

如果主构造器无参数,小括号可省略,构建对象时调用的构造方法的小括号也可以省略。

//(1)如果主构造器无参数,小括号可省略
//class Person (){ 
	class Person {

	var name: String = _ 
    var age: Int = _
        
    def this(age: Int) {
   	 	this() 
    	this.age = age
    	println("辅助构造器")
	}

	def this(age: Int, name: String) { 
    	this(age)
		this.name = name
	}

	println("主构造器")
	}

	object Person {
		def main(args: Array[String]): Unit = { 
            val person2 = new Person(18)
		}
	}

构造器参数
说明

Scala 类的主构造器函数的形参包括三种类型:未用任何修饰、var 修饰、val 修饰

(1) 未用任何修饰符修饰,这个参数就是一个局部变量

(2) var 修饰参数,作为类的成员属性使用,可以修改

(3) val 修饰参数,作为类只读属性使用,不能修改

案例实操
class Person(name: String, var age: Int, val sex: String) {

}

object Test {

def main(args: Array[String]): Unit = {

var person = new Person("bobo", 18, "男")
// (1)未用任何修饰符修饰,这个参数就是一个局部变量
// printf(person.name)

// (2)var 修饰参数,作为类的成员属性使用,可以修改
person.age = 19 println(person.age)
// (3)val 修饰参数,作为类的只读属性使用,不能修改
// person.sex = "女" 
println(person.sex)
}
}

继承和多态

基本语法

class 子类名 extends 父类名 { 类 体 }

(1) 子类继承父类的属性方法

(2) scala 是单继承

案例实操

(1) 子类继承父类的属性方法

(2) 继承的调用顺序:父类构造器->子类构造器

class Person(nameParam: String) {

var name = nameParam 
var age: Int = _

def this(nameParam: String, ageParam: Int) { 
    this(nameParam)
	this.age = ageParam
	println("父类辅助构造器")
}

println("父类主构造器")
}

class	Emp(nameParam:	String,	ageParam:	Int)	extends Person(nameParam, ageParam) {

var empNo: Int = _

def this(nameParam: String, ageParam: Int, empNoParam: Int) { this(nameParam, ageParam)
this.empNo = empNoParam
println("子类的辅助构造器")
}
println("子类主构造器")
}

object Test {
def main(args: Array[String]): Unit = { new Emp("z3", 11,1001)
}
}

(3)Scala 中属性和方法都是动态绑定,而Java 中只有方法为动态绑定。

案例实操(对比 Java 与 Scala 的重写)

Scala

class Person {
val name: String = "person"

def hello(): Unit = { 
    println("hello person")
}
}

class Teacher extends Person {
override val name: String = "teacher" //重写属性
override def hello(): Unit = {
println("hello teacher")
}
}

object Test {
def main(args: Array[String]): Unit = { 
val teacher: Teacher = new Teacher() 
println(teacher.name) 
teacher.hello()

val teacher1:Person = new Teacher 
println(teacher1.name) 
teacher1.hello()
}
}

Java

class Person {

public String name = "person"; public void hello() {
System.out.println("hello person");
}

}
class Teacher extends Person {
public String name = "teacher"; @Override
public void hello() { System.out.println("hello teacher");
}

}
public class TestDynamic {
public static void main(String[] args) {

Teacher teacher = new Teacher();
Person teacher1 = new Teacher();

System.out.println(teacher.name); teacher.hello();

System.out.println(teacher1.name); teacher1.hello();
}
}

抽象类

抽象属性和抽象方法
基本语法

(1) 定义抽象类:abstract class Person{} //通过 abstract 关键字标记抽象类

(2) 定义抽象属性:val|var name:String //一个属性没有初始化,就是抽象属性

(3) 定义抽象方法:def hello():String //只声明而没有实现的方法,就是抽象方法

abstract class Person {
val name: String def hello(): Unit
}

继承&重写

(1) 如果父类为抽象类,那么子类需要将抽象的属性和方法实现,否则子类也需声明为抽象类

(2) 重写非抽象方法需要用 override 修饰,重写抽象方法则可以不加 override。

(3) 子类中调用父类的方法使用 super 关键字

(4) 子类对抽象属性进行实现,父类抽象属性可以用 var 修饰;

子类对非抽象属性重写,父类非抽象属性只支持 val 类型,而不支持 var

因为 var 修饰的为可变变量,子类继承之后就可以直接使用,没有必要重写

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值