变量和数据类型
2.1 注释
Scala注释使用和Java完全一样
- 单行注释://
- 多行注释: /**/
- 文档注释:/**
*
*/
代码规范
- 使用一次tab操作,实现缩进
- 或者使用ctrl+alt+L进行格式化
- 运算符两边习惯性各加一个空格。
- 一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅
2.2 变量和常量
常量:在程序执行过程是不会被改变的变量
- 基本语法
var 变量名 [:变量类型] = 初始值 var i:int = 10
val 常量名 [:常量类型] = 初始值 val j:Int = 20
- 案例实操
- 声明变量时,类型可以省略,编译器自动推导,即类型推导。
- 类型确定后,就不能修改,说明Scala是强数据类型语言。
- 变量声明时,必须要有初始值。
- 在声明/定义一个变量时,可以用var或者val来修饰,var修饰的变量可改变,val修饰的变量不可以修改。
object TestVar {
def main(args: Array[String]): Unit = {
// 1 声明变量时,类型可以省略,编译器自动推导,即类型推导
var age = 18
age = 30
println(age)
// 2 类型确定后,就不能修改,说明Scala是强数据类型语言
// age = "Tom"// 错误
// 3 变量声明时,必须要有初始值
// var name // 错误
//4 在声明/定义一个变量时,可以使用var或者val来修饰,
// var修饰的变量可改变, val修饰的变量不可改
var num1 = 10 // 可变
val num2 = 20 // 不可变
// eg:
num1 = 30
// num2 = 30 // 错误
// 5 var修饰的对象引用可以改变,val修饰的对象则不可以改变,
// 但对象的状态(值)却是可以改变的。(比如:自定义对象、数组、集合等等)
// p1 是var修饰的,p1的属性可以改变,而且p1本身也可以变
var p1 = new Person()
p1.name = "man"
p1 = null
println(p1) // null
// p2是val修饰的,那么p2本身就不可变(即p2的内存地址不能变)
// 但是p2的属性是可以变的,因为属性并没有用val修饰
val p2 = new Person()
p2.name = "chu"
// p2 = null // 错误,因为p2是val修饰的
println(p2) // com.chujun.chapter02.Person@71c7db30 地址
}
}
class Person{
var name : String = "mortal"
}
2.3 标识符的命名规范
Scala对各种变量、方法、函数等命名时使用的字符序列称为标识符。即:凡是自己可以起名字的地方都叫标识符。
- 命名规则
Scala中的标识符声明,基本和Java的是一致的,但是细节上会有所变化,有以下三种规则
- 以字母或下划线开头,后接字母、数字、下划线
- 以操作符开头,且只包含操作符(+-*/#!)
- 用反引号
...
包括的任意字符串,即使是Scala关键字也可以
- 案例实操
object TestName {
def main(args: Array[String]): Unit = {
// 1 以字母或者下划线开头,后接字母数字、下划线
var hello: String = "" // ok
var Hello12: String = "" // ok
// var 1hello: String = "" // error 数字不能开头
// var h-b: String = "" // error 不能用-
// var x h: String = "" // error 不能用空格
var h_4: String = "" // ok
var _ab: String = "" // ok
var Int: String = "" // ok 因为在Scala中Int是预定字符,不是关键字,但是不推荐
// var _: String = "hello" // error 单独一个下划线不可以作为标识符,因为_被认为是一个方法
// println(_)
// 2 以操作符开头,且只包含操作符(+ - * / # !等)
var +-*/#! : String = "" // ok
// var +-*/#!1 : String = "" // error 以操作符开头,必须都是操作符
// 3 用反引号`...`包括的任意字符串,即使是Scala关键字也可以
// var if: String = "" // error 不能用关键字
var `if`: String = "" // ok 用反引号`...`包括的任意字符串,包括关键字
}
}
2.4 字符串输出
- 基本语法
- 字符串,通过+号连接
- printf用法:字符串,通过%传值
- 字符串模板(插值字符串):通过$获取变量值
- 案例实操
object TestStringType {
def main(args: Array[String]): Unit = {
var name: String = "mortal"
var age: Int = 18
// 1 字符串,通过加号连接
println(name+" "+ age) // mortal 18
//2 printf用法字符串,通过%传值
printf("name=%s age=%d\n",name,age) //name=mortal age=18
// 3 多行字符串,在Scala中,利用三个双引号包围多行字符串就可以实现。
// 输入的内容,带有空格、\t之类,导致每一行的开始不能整洁的对其。
// 应用Scala的stripMargin方法,在Scala中stripMargin默认是"|"作为连接符
// 在多行换行的行头前加一个"|"符号即可
val s =
s"""
|select
| name
| ,age
|from user
|where name="mortal"
""".stripMargin
/*输出:
select
name
,age
from user
where name="mortal"
*/
println(s)
// 4 通过$符获取变量的值,如果需要多变量进行运算,那么可以加${}
val s1 =
s"""
|select
| name
| ,age
|from user
|where name="$name" and age=${age+2}
""".stripMargin
/*输出结果
select
name
,age
from user
where name="mortal" and age=20
*/
println(s1)
val s2 = s"name=$name"
println(s2) //name=mortal
}
}
2.5 键盘输入
在编程中,需要接受用户输入的数据,就可以使用键盘输入语句来获取。
- 基本语法
StdIn.readLine()、StdIn.readSort()、StdIn.readDouble()
- 案例实操
import scala.io.StdIn
object TestInput {
def main(args: Array[String]): Unit = {
// 1 输入姓名
println("input name:")
var name = StdIn.readLine()
// 2 输入年龄
println("input age:")
var age = StdIn.readShort()
// 3 输入薪水
println("input salary:")
var sal = StdIn.readDouble()
// 4 打印
println("name:" + name)
println("age:" + age)
println("salary:" + sal)
}
}
2.6 数据类型
- 回顾Java数据类型
Java基本数据类型:char、byte、short、int、long、float、double、boolean
由于Java有基本类型,而且基本类型不是正真意义的对象,即使后面产生了基本类型的包装类,但是仍然存在基本数据类型,所以Java语言并不是真正意思的面向对象。
Java基本类型的包装类:Character、Byte、Integer、Long、Floa、Double、Boolean
注意:Java中基本类型和引用类型没有共同的祖先
- Scala数据类型
- Scala中一切数据都是对象,都是Any的子类。
- Scala中数据类型分为两大类:数值类型(AnyVal)、引用类型(AnyRef),不管是值类型还是引用类型都是对象。
- Scala数据类型仍然遵守,低精度的值类型向高精度值类型,自动转换(隐式转换)
- Scala中的StringOps是对Java中的String增强。
- Unit:对应Java中的void,用于返回值的位置,表示方法没有返回值。Unit是一个数据类型,只有一个对象就是()。void不是数据类型,只是一个关键字。
- Null是一个类型,只有一个对象就是null。它是所有引用类型(AnyRef)的子类。
- Nothing,是所有数据类型的子类,主要用在一个函数没有明确返回值时使用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。
2.7 整数类型(Byte、Short、Int、Long)
Scala的整数类型就是用于存放数值的,比如12,30,1234
- 整型分类
- 案例实操
object TestDataType {
def main(args: Array[String]): Unit = {
// 1、Scala各整数类型有固定的表示范围和字段长度,不受具体操作的影响,以保证Scala程序的可移植性
// 正确
var n1: Byte = 127
var n2: Byte = -128
// 错误
// var n3: Byte = 128
// var n4: Byte = -129
// 2、Scala的整型,默认为Int型,声明Long型,须后加'l'或'L'
// 3、Scala程序中变量常声明为Int型,除非不足以表示大数,才使用Long
var n5 = 10
println(n5)
var n6 = 9223372036854775807L
println(n6)
}
}
2.8 浮点类型(Float、Double)
Scala的浮点类型可以表示一个小数,比如123.4f,7.8,0.12等等
- 浮点数分类
- 案例实操
// 4、Scala的浮点型常量默认为Double型,声明Float型常量,须后加'f'或'F'
// 建议,在开发中需要高精度小数时,请选择Double
var n7 = 2.2345678912f
var n8 = 2.2345678912
println("n7=" + n7) // n7=2.2345679
println("n8=" + n8) // n8 = 2.2345678912
2.9 字符类型(Char)
- 基本说明
字符类型可以表示单个字符
- 案例实操
// 字符类型
// 1、字符常量是用单引号''括起来的单个字符。
var c1: Char = 'a'
println("c1=" + c1)
// 注意:这里涉及自动类型提升,其编译器可以自定判断是否超出范围
// var c2: Char = 'a' + 1
// println(c2)
// 2、\t一个制表位,实现对齐的功能
println("姓名\t年龄")
// 3、\n换行符
println("西门庆\n潘金莲")
// 4、\\表示\
println("c:\\file\\a.txt")
// 5、\" 表示“
println("同学们都说:\"今天天气很好\"")
2.10 布尔类型:Boolean
- 基本说明
- 布尔类型也叫Boolean类型数据只允许取值true和false
- Boolean类型占一个字节
- 案例实操
// 布尔型
var isResult1: Boolean = false
var isResult2: Boolean = true
2.11 Unit类型、Null类型和Nothing类型(重点)
- 基本说明
- 实例操作
// Unit类型用来表示过程,也就是没有明确返回值的函数
// Unit类似Java里的void。只有一个实例(),这个实例也没有实质意义
def sayOk(): Unit = {
}
println(sayOk())
// Null类只有一个实例对象,Null类似于Java中的null引用。
// Null可以赋值给任意引用类型(AnyRef),但不能赋值给值类型(AnyVal)
var cat = new Cat()
cat = null // 正确
// var cat2: Int = null // 错误
// println("cat2:" + cat2)
// Nothing 可以作为没有正常返回值的方法的返回类型,非常直观的告诉你这个方法不会正常返回,
// 而且由于Nothing是其他任意类型的子类,他还能跟要求返回值的方法兼容
def test(): Nothing = {
throw new Exception()
}
test()
2.12 类型转换
2.12.1 数值类型自动转换
当Scala程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为。
- 基本说明
- 自动提升原则:有多种类型的数据混合运算时,系统首先将所有数据转换成精度大的那种数据类型,然后再计算。
- 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
- (byte、short)和char之间不会互相自动转换。
- byte,short,char,他们三者可以计算,在计算时首先转换为Int;类型。
- 案例实操
object TestValueTransfer {
def main(args: Array[String]): Unit = {
// 自动提升原则:有多种类型的数据混合运算时,
// 系统首先将所有数据转换成精度大的那种数据类型,然后再计算。
var n = 1 + 2.0
println(n) // n 就是Double
// 把精度大的数值类型赋值给精度小的数值类型时,就会报错,
// 反之就会进行自动类型转换
var n2: Double = 1.0
// var n3: Int = n2 // 错误,原因不能把高精度的数值直接赋值给低精度
// (byte、short)和char之间不会互相自动转换。
var n4: Byte = 1
// var c1: Char = n4 // 报错
var n5: Int = n4
// byte,short,char,他们三者可以计算,在计算时首先转换为Int;类型。
var n6: Byte = 1
var c2: Char = 1
// var n: Short = n6 + c2 // 当n6 + c2结果类型就时int
// var n7: Short = 10 + 20 // 错误
}
}
2.12.2 强制类型转换
- 基本说明
自动类型转换的逆过程,将精度大的数值类型转换成精度小的数值类型。使用时要加上强制转函数,但可能造成精度低或者溢出,格外注意。
Java: int num = (int) 2.5
Scala: var num: Int = 2.5.toInt
- 案例实操
// 1 将数据由高精度转换为低精度,就需要使用到强制转换
var n1: Int = 2.5.toInt // 这个存在精度缺失
// 2 强转符号只针对于最近的操作数有效,往往会使用小括号提升优先级
var r1: Int = 10 * 3.5.toInt + 6 * 1.5.toInt
var r2: Int = (10 * 3.5 + 6 * 1.5).toInt
println("r1=" + r1) // r1=36
println("r2=" + r2) // r2=44
2.12.3 数值类型和String类型间的转换
- 基本说明
在程序开发中,我们经常需要将基本数值类型转换成String类型,或者将String类型转成基本数值类型。
- 案例实操
object TestValueTransfer2 {
def main(args: Array[String]): Unit = {
// 1 基本类型转String类型(语法:将基本类型的值+""即可)
var str1: String = true + ""
var str2: String = 4.5 + ""
var str3: String = 100 + ""
// 2 String类型转基本数值类型(语法:调用相关API)
var s1: String = "12"
var n1: Byte = s1.toByte
var n2: Short = s1.toShort
var n3: Int = s1.toInt
var n4: Long = s1.toLong
}
}
- 注意事项
在将String类型转成基本数值类型时,要确保String类型能够转成有效的数据,比如我们可以把"123",转成一个整数,但是不能把"hello"转成一个整数。
- 扩展面试题
// 扩展面试题
// 000000000 00000000 00000000 10000010
var n: Int = 130
var b: Byte = n.toByte
// 10000000 为当前字节范围最小值,约定-128
// 负数补码:符号位不变,其它位按取反 + 1
println(b) // -126