前言:在三月份的时候,打算写一本关于Kotlin语言的书,名字都起好了,叫《Kotlin进化之路》,发现,写着写着,自己却没有了那个耐性,索性,整理整理,在公众号里更新吧,这是一个系列,请大家跟上脚步~这篇更新的是:
《Kotlin进化之路》之【第二章:揭开Kotlin的基础面纱】(二)
2.1 基本数据类型
2.1.1:数据类型概括
在Kotlin 中,所有变量的成员方法和属性都是一个对象,一些类型是内建的,它们的实现是优化过的,但对用户来说它们就像普通的类一样,在这节中,将会讲到大多数的类型:数值,字符,布尔,以及数组。
Kotlin 的基本数值类型包括 Byte、Short、Int、Long、Float、Double 等,会Java的同学觉着这个和Java类似,但需要注意的是,字符不属于数值类型,是一个独立的数据类型,具体的数据类型及位宽度,详见图2.1.1.1。
(图2.1.1.1)
上图中忽略了取值范围,其实这个学过Java的同学应该有所了解,对于刚接触到高级语言的同学可能略显生疏,下面我就在列一张表,仔细的来对比一下:
如何去表示一个字面常量,对于十进制的表示方法,我们都会,无非就是:123……,那么其它进制呢?
l16进制表示方法以0x开头:0x0F
这里有一点需要注意,Kotlin是不支持8进制的。
2.1.2:如何去定义一个常量或者变量
定义Kotlin的常量或者变量,它的语法和JavaScript的语法有点类似,用var来定义可变变量,用val来定义不可变变量,基本语法如下:
Var:=
Val:=
在Kotlin中val代表只读,var代表可变,对于这两个,开发中如果你暂时不知道用哪个的时候,我的建议是尽可能多的使用val,因为val是线程安全的,并且必须在定义时初始化,所以不需要担心 null 的问题,只需要注意 val 在某些情况下也是可变的就行了。
对于区别,我的理解如下:
val 和 var 是用于表示属性是否有 getter/setter:
var:同时有 getter 和 setter
val:只有 getter
所以,能用val的地方就用val。
具体使用如下:
vara : Int =66
valb : Int =88
【须知】如果变量或常量的数据类型,有可能采用自动类型推导,那么我们就可以省去类型,直接去赋值也是可以的,这样显得代码更加的简洁:
vala =66
valb =88
注意:由于val是不可变的,如果我们再次赋值,那么就会在编译之前出一个错误:Val cannot be reassigned,提示我们这个不能再重新分配:如图2.1.2.1。
(图2.1.2.1)
对于上面的一小段代码,可能有的同学蒙了,咋没有分号做结尾呢,这里需要说明一点的是,kotlin取消了分割语句的分号,而选择在换行时检查当前parser状态以及下一行第一个token决定是否结束语句,这个和Python的语法有点类似。
对于标识符这里我简单啰嗦几句,在实际的开发中,我希望大家能词能达意,也就是说,自己取得名字得符合公司的规定,让人有一种,见了这个标识符,就知道这个变量或者常量是干嘛用的,当然了,这里的标识符我为了方便,就简单化了。
²所有的标识符都应该以字母(A-Z或者a-z)、或者下划线(_)开始
²首字符之后可以是字母(A-Z或者a-z),下划线(_)或数字的任何字符组合
²关键字不能用作标识符
²标识符是大小写敏感的
²合法标识符举例:age、_value、__1_value
²非法标识符举例:123abc、-salary
举例2.1.2.1,输出各个类型的数据:
打印结果:
对于数据特别大的情况下,比如1000000000这个数值,为了显示的有层次美观,我们可以进行下划线来表示:
vala =1_000_000_000
println(a)
打印结果:
同样,其它类型的数据也可以这样操作,举例2.1.2.2:
funmain(args: Array) {
vala =888_888_888_888L
valb =666_666_666L
valc =0xFF_EC_DE_5E
vald =0b11010010_01101001_10010100_10010010
println(a)
println(b)
println(c)
println(d)
}
打印结果:
888888888888
666666666
4293713502
3530134674
2.1.3:静态类型(理解)
Kotlin 和 Java 一样是一种静态类型的编程语言,这意味着所有表达式的类型在编译期已经确定了,而编译器就能验证对象是否包含了你想访问的方法或者字段。
这与动态类型的编程语言形成了鲜明的对比,后者在JVM 上的代表包括 Groovy 和 JRuby。这些语言允许你定义可以存储任何数据类型的变量,或者返回任 何数据类型的函数,并在运行时才解析方法和字段引用。这会减少代码量并增加创 建数据结构的灵活性。但它的缺点是,在编译期不能发现像名字拼写错误这样的问题,继而导致运行时的错误。
另一方面,与Java 不同的是,Kotlin 不需要你在源代码中显式地声明每个变量 的类型。很多情况下,变量类型可以根据上下文来自动判断,这样就可以省略类型声明。这里有一个可能是最简单的例子 :
val x = 1
在声明这个变量时,由于变量初始化为整型值,Kotlin 自动判断出它的类型是 Int。编译器这种从上下文推断变量类型的能力被称作类型推导。
下面罗列了一些静态类型带来的好处:
性能——方法调用速度更快,因为不需要在运行时才来判断调用的是哪个方法。
可靠性——编译器验证了程序的正确性,因而运行时崩溃的概率更低。
可维护性——陌生代码更容易维护,因为你可以看到代码中用到的对象的类型。
工具支持——静态类型使 IDE 能提供可靠的重构、精确的代码补全以及其他 特性。
得益于Kotlin 对类型推导的支持,你不再需要显式地声明类型,因此大部分关 于静态类型的额外冗长代码也就不复存在了。
当你检视Kotlin 类型系统的细节时,你会发现许多熟悉的概念,类、接口以及 泛型和 Java 非常接近,所以大部分的 Java 知识可以很容易地转移到 Kotlin,然而, 也会有一些新概念出现。
其中最重要的概念是Kotlin 对可空类型的支持,通过在编译期检测可能存在的 空指针异常,它让你可以写出更可靠的程序。
另一个Kotlin 类型系统的新概念是对函数类型的支持,要搞清楚这一点,我们先要了解函数式编程的主要思想,以及 Kotlin 是如何支持这种编程风格的。
2.1.4:类型转换
在开发中,我们经常会遇到数据类型之间的转换,在Kotlin中由于表示方法的不同,较小类型并不是较大类型的子类型,较小的类型不能隐式转换为较大的类型,意味着在不进行显示转换的情况下我们不可以把Byte类型赋值给一个Int类型,如图2.1.4.1:
(图2.1.4.1)
2.1.4.1:显示转换
较小的类型不会被隐式转换为更大的类型,故而系统提供了显式转换,提供的显式转换方法如下:
ØtoByte() =>转换为字节型
ØtoShort() =>转换为短整型
ØtoInt() =>转换为整型
ØtoLong() =>转换为长整型
ØtoFloat() =>转换为浮点型
ØtoDouble() =>转换为双精度浮点型
ØtoChar() =>转换为字符型
ØtoString() =>转换为字符串型
举例2.1.4.1:
funmain(args: Array) {
vara: Int =88
println(a.toByte())
println(a.toShort())
println(a.toInt())
println(a.toLong())
println(a.toFloat())
println(a.toDouble())
println(a.toChar())
println(a.toString())
}
打印结果:
2.1.4.2:隐式转换
类型是从上下文推断出来的,即算术运算则被重载为适当的转换
举例2.1.4.2:
funmain(args: Array) {
valnum =88L+88//Long + Int => Long
print(num)
}
打印结果:
176
2.1.5:字符型(Char)
和Java 不一样,Kotlin 中的 Char 不能直接和数字操作,Char 必需是单引号 ' 包含起来的,比如普通字符 '0','a'。
funmain(args: Array) {
varchar1: Char
char1 ='a'
char1 =1//这句代码会直接出错
println("char1 =>$char1")
}
字符型的变量不仅可以转换为数字,同时也可转换为其他类型,举例2.1.5.1:
funmain(args: Array) {
varchar1:Char='a'
varvar1 = char1.toByte()
varvar2 = char1.toInt()
varvar3 = char1.toString()
varvar4 = char1.toFloat()
varvar5 = char1.toShort()
println("var1 =>$var1\nvar2 =>$var2\nvar3 =>$var3\nvar4 =>$var4\nvar5 =>$var5")
}
打印结果:
var1 =>97
var2 =>97
var3 => a
var4 =>97.0
var5 =>97
除了可以转换类型外,当变量为英文字母时还支持大小写转换,举例2.1.5.2:
funmain(args: Array) {
/*
当字符变量为英文字母时,大小写的转换
*/
varcharA: Char ='a'
varcharB: Char ='B'
varcharNum: Char ='1'
varresult: Char
// 转换为大写
result = charA.toUpperCase()
println("result =>$result")
// 转换为小写
result = charB.toLowerCase()
println("result =>$result")
//当字符变量不为英文字母时,转换无效
result = charNum.toLowerCase()
println("result =>$result")
}
打印结果:
result => A
result => b
result =>1
字符转义同Java一样,使用某些特殊的字符时,要使用转义。下列是支持的转义序列:
Ø\t => 表示制表符
Ø\n => 表示换行符
Ø\b => 表示退格键(键盘上的Back建)
Ø\r => 表示键盘上的Enter键
Ø\\ => 表示反斜杠
Ø\' => 表示单引号
Ø\" => 表示双引号
Ø\$ => 表示美元符号,如果不转义在kotlin中就表示变量的引用了
Ø其他的任何字符请使用Unicode转义序列语法。例:'\uFF00'
举例2.1.5.3:
funmain(args: Array) {
println("\n换行符")
println("\t制表符")
println("\b退格键")
println("\rEnter键同样换行")
println('\\')
println('\'')
println('\"')
println('\$')
println('\uFF01')
}
打印结果:
换行符
制表符
退格键
Enter键同样换行
\
'
"
$
!
2.1.6:布尔类型(Boolean)
Boolean关键字表示布尔类型,并且其值有true和false
举例2.1.6.1:
funmain(args: Array) {
varboolTrue:Boolean=true
varboolFalse:Boolean=false
println(boolTrue)
println(boolFalse)
}
打印结果:
true
false
2.1.7:可空类型
一门新的语言的诞生总有它特定的和别的语言不同的一点,Kotlin也不例外,Kotlin语言与Swift语言类似,默认情况下所有的数据类型都是非空类型(Non-Null),声明的变量都是不能接收空值(null)的,这一点与Java和Objective-C等语言有很大的不同。
Kotlin的非空类型设计可以防止空指针异常(NullPointerException),在Kotlin中如果将一个对象的声明为非空类型,那么它就永远不会接收空值,否则会发生编译错误。
代码演示:
funmain(args: Array) {
vara:Int =66
a =null
}
上述代码会抛出一个异常,因为Int是非空类型,它所声明的变量a不能接收空值,但有些场景确实没有数据,例如查询数据库记录时,没有查询出符合条件的数据是很正常的事情,为此,Kotlin为每一种非空类型提供对应的可空类型(Nullable),就是在非空类型后面加上问号(?)表示可空类型。
修改后代码则就没有了问题:
funmain(args: Array) {
vara:Int? =66
a =null
}
Int?是可空类型,它所声明的变量a可以接收空值,可空类型在具体使用时会有一些限制:
Ø不能直接调用可空类型对象的函数或属性。
Ø不能把可空类型数据赋值给非空类型变量。
Ø不能把可空类型数据传递给非空类型参数的函数。
为了“突破”这些限制,Kotlin提供了如下运算符:
Ø安全调用运算符:?.
Ø安全转换运算符:as?
ØElvis运算符:?:
Ø非空断言:!!
Ø此外,还一个let函数帮助处理可空类型数据。
领取专属 10元无门槛券
私享最新 技术干货