变量和数据类型

2.1 注释

Scala注释使用和Java完全一样

  1. 单行注释://
  2. 多行注释: /**/
  3. 文档注释:/**
    *
    */

代码规范

  1. 使用一次tab操作,实现缩进
  2. 或者使用ctrl+alt+L进行格式化
  3. 运算符两边习惯性各加一个空格。
  4. 一行最长不超过80个字符,超过的请使用换行展示,尽量保持格式优雅

2.2 变量和常量

常量:在程序执行过程是不会被改变的变量

  • 基本语法

var 变量名 [:变量类型] = 初始值 var i:int = 10
val 常量名 [:常量类型] = 初始值 val j:Int = 20

  • 案例实操
  1. 声明变量时,类型可以省略,编译器自动推导,即类型推导。
  2. 类型确定后,就不能修改,说明Scala是强数据类型语言。
  3. 变量声明时,必须要有初始值。
  4. 在声明/定义一个变量时,可以用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的是一致的,但是细节上会有所变化,有以下三种规则

  1. 以字母或下划线开头,后接字母、数字、下划线
  2. 以操作符开头,且只包含操作符(+-*/#!)
  3. 用反引号...包括的任意字符串,即使是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 字符串输出

  • 基本语法
  1. 字符串,通过+号连接
  2. printf用法:字符串,通过%传值
  3. 字符串模板(插值字符串):通过$获取变量值
  • 案例实操
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数据类型
  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,是所有数据类型的子类,主要用在一个函数没有明确返回值时使用,因为这样我们可以把抛出的返回值,返回给任何的变量或者函数。

img

2.7 整数类型(Byte、Short、Int、Long)

Scala的整数类型就是用于存放数值的,比如12,30,1234

  • 整型分类

img

  • 案例实操
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等等

  • 浮点数分类

img

  • 案例实操
    // 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

  • 基本说明
  1. 布尔类型也叫Boolean类型数据只允许取值true和false
  2. Boolean类型占一个字节
  • 案例实操
    // 布尔型
    var isResult1: Boolean = false
    var isResult2: Boolean = true

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

  • 基本说明

img

  • 实例操作
    // 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程序在进行赋值或者运算时,精度小的类型自动转换为精度大的数值类型,这个就是自动类型转换(隐式转换)。数据类型按精度(容量)大小排序为。

img

  • 基本说明
  1. 自动提升原则:有多种类型的数据混合运算时,系统首先将所有数据转换成精度大的那种数据类型,然后再计算。
  2. 把精度大的数值类型赋值给精度小的数值类型时,就会报错,反之就会进行自动类型转换。
  3. (byte、short)和char之间不会互相自动转换。
  4. 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