目录
一、变量
变量声明一定要初始化
val
修饰的变量,相当于
Java
中
fifinal
修饰的变量
;
// 定义常量 s1 ,使用字符串 "1" 赋值,自动推断为 String 类型,值不可变val s1 = "1"// 定义常量 s2 ,手动指定类型为 String ,此时需要保证所赋值类型匹配val s2 : String = "2"// 使用 val 定义基本数据类型时,值不可变,可以使用 val 重新定义
1.1变量推断
含义:声明变量时,可以不指定变量类型,编译器会根据赋值内容自动推断当前变量的类型。
// 定义变量a1,使用1赋值,自动推断为Int类型
var i1 = 1
print(i1.isInstanceOf[Int])
//类型确定后,就不能再赋值的类型
i1 = 1.1
1.2多变量定义
//Java中支持一行同时定义多个同类变量:
String a = "Hello", c = "hello";
int x = 5, y = 5;
//scala中的多个变量的初始化:
val (a, b, c) = (1, 2, "a")
// 定义变量a3,a4,同时赋值为10
var i3,i4 = 10;
1.3var和val的区别
# val 和 var 的区别- 是否可变- 是否可以有 lazy 修饰 : 延迟加载
1.3.1是否可变
使用val声明一个常量或值:
val
修饰的变量是不可变的,注意不可变的是引用,而不是内容
,
==val
修饰的变量在编译后,等同于加上fifinal==
。
使用var
声明一个变量:
var
修饰的变量,内容和引用都可变
(扩展一下什么是值类型,什么是引用类型,可以使用数组举例,引用不可变,变的是内容。)
可变和不可变?
可变和不可变,指的是变量本身存的内容,值类型变量存的是数据本身,而引用类型变量存的是数据的引用,
值类型和引用类型?
值类型与引用类型区别:
存储方式 :直接存储数据本身
vs
存储的是数据的引用,数据存储在数据堆中
内存分配 :分配在栈中
vs
分配在堆中
效率 :效率高,不需要地址转换
vs
效率较低,需要进行地址转换
内存回收
:
使用完后立即回收
vs
使用完后不立即回收,而是交给
GC
处理回收
//定义了一个数组,arr存储的是一个地址在栈区,Array(1, 2, 3, 4, 5) 才是真正存储数据的在堆区,
//arr的地址指向Array(1, 2, 3, 4, 5)这个数组
scala> val arr = Array(1,2,3,4,5)
arr: Array[Int] = Array(1, 2, 3, 4, 5)
//改变arr地址的指向
scala> arr = Array(1,2,3)
//错误,发现不能改,这就是因为arr是val定义的,不能改
<console>:8: error: reassignment to val arr = Array(1,2,3)
//修改arr指向的数组里面的值
scala> arr(0)=10
//发现修改成功
//注意这个val不能改的是arr而arr存储的是指向那个数组的地址
//修改成功的是修改被指向的数组里面的值
//而不是修改arr存储的地址,所以成功
scala> arr
res1: Array[Int] = Array(10, 2, 3, 4, 5)
1.3.2延迟加载
只有val
修饰的变量才能被
lazy
修饰
,使用
lazy
定义变量后,
==
只有在调用该变量时才会实例化这个变量的值
==
,类似方法,先声明,后调用。
scala> val a = 10
a: Int = 10
scala> lazy val b = 100
b: Int = <lazy>
scala> b
res2: Int = 100
scala> var c = 10
c: Int = 10
scala> lazy var d = 100
<console>:1: error: lazy not allowed here. Only vals can be lazy lazy //懒加载var的错误
var d = 100
^
scala> def e = 1000
e: Int
scala> e
res3: Int = 1000
注意:lazy的变量在定义是时候不会加载到内存,只有在使用这个变量的时候才会加载
1.3.3使用val 还是var?
#
官方推荐
val,
使用
val
的好处:
- 更安全
- 代码可读性更高
- 资源回收更快,方法执行完,
val
所定义的变量即回收
二、类型
2.1类型层级关系
# Any是所有类型的父类
它定义了一些通用的方法如equals、hashCode和toString。Any有两个直接子类:AnyVal和AnyRef。
# AnyVal 是所有值类型的父类有9 个预定义的非空的值类型分别是: Double 、 Float 、 Long 、 Int 、 Short 、 Byte 、 Char 、 Unit 和 Boolean 。Unit是不带任何意义的值类型,它仅有一个实例可以像这样声明: () 。所有的函数必须有返回,所以说有时候 Unit 也是有用的返回类型。# AnyRef 是所有引用类型的父类AnyRef代表引用类型。所有非值类型都被定义为引用类型。在 Scala 中,每个用户自定义的类型都是 AnyRef 的子类型。如果Scala 被应用在 Java 的运行环境中, AnyRef 相当于 java.lang.Object 。# Nothing 是所有类型的子类Nothing是所有类型的子类,也是 Null 的子类,他没有一个具体的实例对象,常见的应用如:抛出异常、程序exit,无限循环等,返回值为 Nothing 类型。Nothing没有对象,但是可以用来定义类型。例如,如果一个方法抛出异常,则异常的返回值类型就是 Nothing(虽然不会返回 ) 。def get(index:Int):Int = {if(x < 0) throw new Exception(...) //返回值类型Nothingelse ....}# Null 是所有引用类型的子类Null只有一个实例对象 null ,主要用来和其他的 JVM 语言进行互操作,但是几乎不应该在 Scala 代码中使用。
Scala 与 Java有着相同的数据类型:
数据类
型
|
描述
|
Byte
|
8
位有符号补码整数。数值区间为
-128
到
127
|
Short
|
16
位有符号补码整数。数值区间为
-32768
到
32767
|
Int
|
32
位有符号补码整数。数值区间为
-2147483648
到
2147483647
|
Long
|
64
位有符号补码整数。数值区间为
-9223372036854775808
到
9223372036854775807
|
Float
|
32
位
, IEEE 754
标准的单精度浮点数
|
Double
|
64
位
IEEE 754
标准的双精度浮点数
|
Char
|
16
位无符号
Unicode
字符
,
区间值为
U+0000
到
U+FFFF
|
String
|
字符序列
|
Boolean
|
true
或
false
|
Unit
|
表示无值,和其他语言中
void
等同。用作不返回任何结果的方法的结果类型。
Unit
只有一个实例
值,写成
()
。
|
Null
|
null
|
Nothing
|
Nothing
类型在
Scala
的类层级的最低端;它是任何其他类型的子类型。
|
Any
|
Any
是所有其他类的超类
|
AnyRef
|
AnyRef
类是
Scala
里所有引用类
(reference class)
的基类
|
Scala数据类型的位数,不受具体OS的影响,以保证Scala程序的可移植性。
2.2值类型AnyVal
Scala和
Java
一样,有
8
种数值类型
Byte
、
Char
、
Short
、
Int
、
Long
、
Float
、
Double
和一个
Boolean
类型,和
Java不同的是 ,Scala
没有基本类型与包装类型之分,这些类型都是类,有自己的属性和方法。
// 相当于Java的包装类;
1.toString()
1.to(10)
常见的类型我就不一 一说了 转义字符跟其他的一样
Unit
类型
// Unit为空类型,相当于void,使用()进行初始化
var u = ()
2.3非值类型
AnyRef
(引用类型)包括
List
、
String
以及自定义类等。
2.3.1字符串类型
上图没有,但也是属于这里,这个比较特殊,属于这里,但使用的各性质跟数值类型一样
String
类型是有双引号包含的一个或者多个字符组成,语法和字符类型基本一致。
val hello = "hello"
val escapes = "\\\"\'"
Scala
中引入的
三引号
作为字符串的开始和结束符,内部的原始字符串可以包含换行、引号和特殊字符
println("""welcome to
"1000phone".""")
//为了解决每行的空格,引入了stripMargin方法。使用方式是把管道符号(|)放在每行前面,然后对整个字符串 调用该方法。
println("""|welcome to
|"1000phone".""".stripMargin)
2.3.3符号类型
Symbol类型也可以描述字符串,相比较于String类型,有两个比较明显的特点:节省内存和快速比较。
scala> val symbol1=Symbol("hello")
symbol1: Symbol = 'hello
scala> val symbol2='hello //等价于Symbol("hello")
symbol2: Symbol = 'hello
scala> symbol1==symbol2
res16: Boolean = true
scala> symbol1.name
res20: String = hello
标识符
是符号字面量(
character literal
)的写法,这里
<
标识符
>
可以是任何字母或数字的标识,但不能以数字开头,符号字面量被映射scala.Symbol
的实例。
2.3.4Option类型
Scala Option(选项)类型用来表示一个值是可选的(有值或无值)
。
Option
有两个子类,分别是
Some
和
None
。
Option[T] 是一个类型为
T
的可选值的容器:
- 如果值存在, Option[T] 就是一个 Some[T]
-
如果不存在, Option[T] 就是对象 None
scala> val name:Option[String]=Some("Jason") //Option[T],这里T是String,是泛型写法
name: Option[String] = Some(Jason)
scala> name.get
res3: String = Jason
scala> val age:Option[Int]=None
age: Option[Int] = None
scala> age.get //age为None,调用get方法报错
java.util.NoSuchElementException: None.get
at scala.None$.get(Option.scala:347)
at scala.None$.get(Option.scala:345)
... 32 elided
scala> age.getOrElse(0) //防止age为None,指定默认值0
res5: Int = 0
注意
:用户自行定义的类均为
AnyRef
类型。
2.4其他类型
Any
// Any可以接收任意的基本类型和引用类型
var any: Any = null
any = anyR //anyR:AnyRef
any = anyV //anyR:AnyVal
AnyRef
// 可以使用AnyRef接收任意的引用类型
var anyR: AnyRef = null
在 Scala
中,字符串的类型实际上是
Java String
,它本身没有
String
类。 在
Scala
中,
String
是一个不可变的
对象,所以该对象不可被修改。这就意味着你如果修改字符串就会产生一个新的字符串对象。
AnyVal
// 可以使用AnyVal接收任意的基本类型
var anyV: AnyVal = u // Unit
anyV = b1 // Boolean
anyV = b // Byte
anyV = s // Short
anyV = c // Char
anyV = i // Int
anyV = f // Float
anyV = l // Int
anyV = d // Double
anyV = str // String
Null
// null值只能被推断为Null类型,null代表空值,可以被赋值给任何
AnyRef类型的常量或变量 var n = null
Nothing
/*Nothing类型在Scala的类层级的最底端,它是任何其他类型的子类型。 当一个函数,我们确定没有正常
的返回值,可以用Nothing 来指定返回类型,这样有一个好处,就是我们可以把返回 的值(异常)赋给其
它的函数或者变量(兼容性)。前面None类型就应用了该特点:*/
case object None extends Option[Nothing] {
def isEmpty = true
def get = throw new NoSuchElementException("None.get") //get方法返回Nothing类型
}
三、类型转换
3.1 自动类型转换
val x: Long = 987654321
val y: Float = x // 9.8765434E8 (note that some precision is lost in this case)
val face: Char = '☺'
val number: Int = face // 9786
当Double转为Int时,错误如下:
scala> val i:Int=10d
<console>:11: error: type mismatch;
found : Double(10.0)
required: Int
val i:Int=10d
当Char转整型时:
scala> val a:Byte='a' //英文1个字节,正确
a: Byte = 97
scala> val a:Byte='我' //中文2个字节,所以报错
<console>:11: error: type mismatch;
found : Char('我')
required: Byte
val a:Byte='我'
scala> val a:Short='我' //正确
a: Short = 25105
scala> val a:Int='我' //正确
a: Int = 25105
scala> val a:Float='我'
a: Float = 25105.0
小结:低位数可以向高位数数转换。如 Byte->Short字符可以转整形或浮点型,不同长度字符应使用不同位数的整型整型可以转浮点型,允许精度丢失。如 Long->Float
3.2强制类型转换
scala
中转换:
//toByte toChar toDouble toFloat toInt toLong
//toShort toString
scala> val a = 19.9
a: Double = 19.9
scala> val b = a.toInt
b: Int = 19
scala> val c=a.asInstanceOf[Int] //类似Java中的强制类型转换:(int)a
c: Int = 19
Scala
与
Java
类型检查和转换对比
Scala
|
Java
|
obj.isInstanceOf[C]
|
obj instanceof C
|
obj.asInstanceOf[C]
|
(C)obj
|
classOf[C]
|
C.class
|
3.3数值类型和字符串类型的转换
数值类型转字符串类型
val s1 = true+""
val s2 = 3.1415+""
val s3 = 100 +""
字符串类型转数值类型
val s4 = "3.14"
s4.toDouble()