Kotlin——数据的基本表现形式及基本运算符小结

来源:互联网 发布:秦淮数据有限公司招聘 编辑:程序博客网 时间:2024/05/22 15:14

引言

前面一篇简单的总结了下入门Kotlin的第一步——配置开发环境引入Kotlin库,接下来正式踏入Kotlin的世界。Kotlin是诞生于多年前年的一种程序语言,对,就是一套完整的程序语言,而且Kotlin本身是一种完全面向对象的,万物皆对象(意味着可以在任何变量上调⽤成员函数和属性),而构成对象的变量类型多种多样,这就需要不同的数据类型支持,有些类型是内置的,因为他们的实现是优化过的(因为Kotlin本质上是一种JVM语言),但是看起来他们就像普通的类,学习Kotlin语法的时候可以到在线编写运行Kotlin代码

一、数据的基本类型

在Kotlin中,数据的类型和大多数程序语言一样也分为五种:数字字符布尔数组字符串类型。

二、数字类型

Kotlin 处理数字类型的数据在某种程度上和Java大同小异,在Kotlin中对于数字没有隐式类型自动转换(在Java中转换按数据长度增加的方向进行,以保证精度不降低,所有的浮点运算都是以双精度进行的,即使仅含float单精度量运算的表达式,也要先转换成double型,再作运算,char型和short型参与运算时,必须先转换成int型,在赋值运算中,赋值号两边的数据类型不同时,需要把右边表达式的类型将转换为左边变量的类型等),Kotlin处理数字类型的数据根据精度不同也分为6种:Double、Float、Int、Long、Short、Byte

类型 所占字节 Double 64 Float 32 Long 64 Int 32 Short 16 Byte 8

1、整数类型

在Kotlin中整数类型数据使用根据精度不同分别使用IntLongShortByte,而且根据进制不同还可以分为十进制、二进制和16进制(不支持8进制)。

  • ⼗进制: 9080980,Long 类型⽤⼤写 L 标记: 9080980L
  • ⼗六进制: 0x0FF,前缀用0x
  • ⼆进制: 0b00001011

2、浮点型

而浮点型根据精度不同分别使用DoubleFloat,小数默认使用Double类型,而使用F或f标识Float类型

3、数字常量中的下划线

从Kotlin 1.1起,也许是为了方便阅读高数字的需要,在一个数字常量中的任意位置(非头部和尾部)插入一个“_”,可以看成一个简单的连接符,无论是任何进制的数字,也不管是小数还是整数都支持。

val oneMillion = 1_000_000.4val creditCardNumber = 1234_56_78_9012_3456Lval socialSecurityNumber = 999_99_9999Lval hexBytes = 0xFF_EC_DE_5Eval bytes = 0b11010010_01101001_10010100_10010010

4、数字的拆箱和装箱

通常数字是以拆箱的形式物理存储为 JVM 的原⽣类型,而当我们需要⼀个可空的引⽤(如 Int? )或泛型才会把数字装箱,装箱操作不会保留同⼀性。基本类型只有值,可以理解成是什么值就是什么值没有别的, 即使声明的时候没有赋值,系统也会默认的给他一个默认值0。而装箱基本类型不同,两个装箱基本类型可以具有相同的值,并且还可以有不同的同一性,比如他们的引用地址不同。

  • 装箱:把基本类型用它们相应的引用类型包装起来,使其具有对象的性质。

  • 拆箱:和装箱相反,将引用类型的对象简化成值类型的数据

数字装箱的时候不一定持有同一性

val a: Int = 10000print(a === a) // 输出“true”val boxedA: Int? = aval anotherBoxedA: Int? = aprint(boxedA === anotherBoxedA) // !!!输出“false”!!!,因为boxedA和anotherBoxedA不是同一个对象

数字装箱的时候保持了自等性

 val a: Int = 10000 print(a == a) // 输出“true” val boxedA: Int? = a val anotherBoxedA: Int? = a print(boxedA == anotherBoxedA) // 输出“true”,值相等

5、数字之间的显式转换

所谓的显式转换即强转,实现也很简单只需要调用对应的方法即可

  • toByte()——Byte
  • toShort()——Short
  • toInt()——Int
  • toLong()——Long
  • toFloat()——Float
  • toDouble()—— Double
  • toChar()—— Char

6、Long和Int型数字的位运算

位运算应该是效率最高的运算,对于位运算,没有特殊字符来表⽰,⽽只可⽤中缀⽅式调⽤命名函数,例如:val x = (1 shl 2) and 0x000FF000
- shl(bits) ——有符号左移 (Java 的 << )
- shr(bits) —— 有符号右移 (Java 的 >> )
- ushr(bits) ——⽆符号右移 (Java 的 >>> )
- and(bits) ——按位与
- or(bits) ——按位或
- xor(bits) ——按位异或
- inv() ——按位⾮

三、字符

Kotlin中字符⽤ Char 类型表⽰,字符常量用单引号’ ‘括起来,特殊字符可以⽤反斜杠转义(⽀持以下转义序列:\t 、 \b 、\n 、\r 、\’ 、\” 、\ 和 $ ) 编码其他字符要⽤Unicode 转义序列语法:’\uFF00’ ,且与Java不同它们不能直接当作数字(Java中字符的值对应着ASCCII值),最后当需要可空引⽤时,像数字、字符类型会自动被装箱,但装箱操作不会保留同⼀性。

四、布尔

布尔⽤ Boolean 类型表⽰,和Java它有两个值:true 和 false,若需要可空引⽤布尔会被自动装箱。
内置的布尔运算有:

  • || —— 短路逻辑或
  • && ——短路逻辑与
  • ! ——逻辑⾮

五、字符串

字符串⽤ String 类型表⽰,字符串是不可变的。 在Kotlin中是可以使⽤索引运算符访问字符串的字符也可以⽤ for 循环遍历字符串。

//直接索引访问 c[2]for (c in str) {    println(c)}

1、 转义字符串和**原始字符串

另外在Kotlin中有两种类型的字符串常量: 转义字符串原始字符串,可以有转义字符(转义采⽤传统的反斜杠⽅式),转义字符串很像 Java 字符串而在实际使用中字符串可能还会包含转义符、系统保留关键字等特殊字符,为了更好地区分,Kotlin特别定义了一个所谓的原始字符串(原始字符串由三重引号(”“” “”“)分隔,不包含转义,不能包含换行符和其他字符),简单来说就是三重引号内的一切特殊字符绝不做额外处理仅仅看成是一个普通的字符。

 val text = """    for (c in "foo")        print(c)        \n    """    println(text)/**输出 for (c in "foo")                    print(c)                    \n                     */

2、字符串模板

Kotlin字符串中还可以包含模板表达式 ,这些表达式不会被当成普通字符来处理而是会当成一个运算表达式来完成运算得到结果,然后再把结果替换掉表达式,简单地可以看成是这个表达式当做占位符的功能。 模板表达式以美元符( $ )开头

val i = 10val s = "i = $i" // 求值结果为 "i = 10"val s = "abc"val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"

原⽣字符串和转义字符串内部都⽀持模板。 如果你需要在原⽣字符串中表⽰字⾯值 $ 字符(它不⽀持反斜杠转义),你可以这样用

val price = """${'$'}9.99"""

六、数组

在 Kotlin 中数组使用Array 类来表⽰,它定义了 get 和 set 函数(按照运算符重载约定这会转变为 [] )和 size 属性,以及⼀些其他有⽤的成员

1、数组的创建

创建数组实例主要有四种方式:Array(size: Int, init: (Int) -> T)arrayOf()arrayOfNullsemptyArray 函数直接创建。

  • arrayOf()——返回指定元素的数组
  • arrayOfNulls ——返回指定类型的数组并用null初始化
  • emptyArray——返回指定类型的空数组
val asc = Array(5, { i -> (i * i).toString() })//遍历数组for(v in asc){    println(v)}//遍历数组下标for (arr in asc.indices) {    println(arr)}val arr = arrayOf(1, 2, 3);for (item in arr) {    println(item);}//创建原始整形数组val numbers: IntArray = intArrayOf(10, 20, 30, 40, 50)var numbers: IntArray = IntRange(10, 50).step(10).toList().toIntArray()//长度为0的空数组val empty = emptyArray<Int>()

最后,与 Java 不同的是,Kotlin 中数组是不型变的(invariant)。这意味着 Kotlin 不让我们把 Array<String> 赋值给 Array<Any> ,以防⽌可能的运⾏时失败(但是你可以使⽤ Array<out Any> )。Kotlin 也有⽆装箱开销的专⻔的类来表⽰原⽣类型数组: ByteArray 、 ShortArray 、IntArray 等,虽然这些类和 Array 并没有继承关系,但是它们有同样的⽅法属性集。

七、运算符

计算机程序中最小的程序单位成为表达式,每个表达式都可以由两部分组成,即操作数和运算符。操作数可以是变量、常量、类、数组、方法等,甚至是其他表达式。而运算符则用于支持表达式中单个或者多个操作数参与运算的规则,表达式通过运算之后产生的值依赖于表达式中包含的运算符的优先级。Kotlin语言包含了Java语言中的所有运算符的特性,并结合C语言的优点,增加自定义运算符的逻辑。这些运算符之中,主要包括有:算数运算符区间运算符逻辑运算符关系运算符赋值运算符自增自减运算符等。根据操作数的数量来划分,运算符又可以分为一目运算符双目运算符。,而且各运算符之间优先级各不相同如下表所示:
这里写图片描述

1、赋值运算符 “=”

赋值运算a=b,表示等号右边的b初始化或者维护等号左边的a,b可以是变量、常量、字面量或表达式

var IntA:Int = 25val IntB:Int = 100IntA = 29 + 1;IntA = IntB

同样的还有另一种赋值运算符,叫做算术自反赋值运算符。它是一种由两个普通运算符组成的符合运算符,它包括:+=-=*=/=%=

var IntA:Int = 59val IntB:Int = 10IntA += IntB // 作用等于 IntA = IntA + IntBIntA -= IntB // 作用等于 IntA = IntA - IntBIntA *= IntB // 作用等于 IntA = IntA * IntBIntA /= IntB // 作用等于 IntA = IntA / IntBIntA %= IntB // 作用等于 IntA = IntA % IntB

2、算术运算符

算术运算符用于数值类型的运算,Kotlin语言支持基本的算术运算:加法“+”减法“-”乘法“*”除法“/”取余“%”、以及自增自减运算 “++” 和“–”

var IntA:Int = 5 + 5  // 10val IntB:Int = 10 - 2 // 8val IntC:Int = 3 * 4  // 12val IntD:Int = 10 / 5 // 2val IntE:Int = 10 % 3 // 1,除不尽,保留余数val IntF:Int = 10 / 6 // 1,除不尽,仅保留整数部分IntA = IntA / 0 // 报错,除数不能为0var intA : Int = 5intA++ // 等于 intA = intA + 1println("intA = " + intA)  // 输出 intA = 6

对于自增运算和Java类似还分为前置和后置

var intIncA: Int = 5var intIncB: Int = 5var intIncC: Int = 5var intIncD: Int = 5println(++intIncA) // 先自增, 后返回。 输出 :6println(--intIncB) // 先自减, 后返回。 输出 :4println(intIncC--) // 先返回, 后自减。 输出 :5println(intIncD++) // 先返回, 后自增。 输出 :5

3、字符串连接符 “+”

两个字符串可以连接在一起成为一个新字符串即字符串连接

"hello " + "world" // 等于 "hello world"

字符串连接操作两边都是字符串,而很多情况下我们使用连接符仅有一侧是字符串,另一侧是其他类型。这个时候,系统则会自动调用toString方法转化为字符串,进行拼接。这个时候则调用则是String重载的plus方法,而Kotlin中String的源码如下:

<code>这里写图片描述</code>

故此,进行字符串与其他类型拼接我们都将String类型的操作符至于连接符 “+” 左侧。

var intA : Int = 1var StringA : String = "String Head "println(intA + StringA) // 报错,调用的是Int.plus方法println(StringA + intA) // 输入内容:String Head 1

4、关系运算符

使用关系运算符对两个操作数或表达式进行运算,产生的结果为真或者假,即为关系运算。而且关系运算符的优先级低于算术运算符,但高于赋值运算符

println(10 == 10) // trueprintln(1 != 5)   // trueprintln(1 < 5)    // trueprintln(1 > 5)    // falseprintln(4 <= 5)   // trueprintln(4 >= 5)   // false

5、区间运算符

可以用来表示两个操作数之间的范围集合,类似数学中的集合运算。在Kotlin语言之中,有两种区间运算符:闭区间运算符开区间运算符

  • 闭区间运算符 —— “a..b”从a到b范围内所有的值,包括a和b,相当于数学中的[a,b]
  • 半闭区间运算符 ——“a until b”从a到b范围内所有的值,包括a和不包括b,相当于数学中的[a,b)

区间表达式由具有操作符形式 “..”rangeTo 辅以 in!in ,其中区间是为任意可比较类型定义的,但对于原生类型整型区间有一个额外的特性:它们可以迭代。 Kotlin编译器负责将其转换为类似 Java 的基于索引的 for循环而无额外开销。

/**in 代表在区间内,!in表示不在。*/for (i in 1..10) { // 等同于 1 <= i && i <= 10    println(i)}for (i in 1.rangeTo(10)) {  // 等同于 1 <= i && i <= 10    println(i)}for (i in 'a'..'z') { // 等同于 'a' <= i && i <= 'z'    println(i)}for (i in 1..4) print(i) // 输出“1234”for (i in 4..1) print(i) // 什么都不输出for (i in 4 downTo 1) print(i) // 借助downTo逆序,输出“4321”for (i in 1..4 step 2) print(i) // 借助step 自定义迭代步长,输出“13”for (i in 4 downTo 1 step 2) print(i) // 输出“42”for (i in 1 until 10) {   //创建半开区间 i in [1, 10) 排除了 10     println(i)}

6、逻辑运算符

Kotlin语言和Java一样,支持三个标准逻辑运算符,逻辑与、逻辑或、逻辑非。

  • && —— 逻辑与,可以理解为并且的意思.
  • || —— 逻辑或,可以理解为或者的意思,也就是条件可以二取一
  • —— 逻辑非,取反
    这里写图片描述

7、空安全操作符“?”和 “!!”

在Kotlin语言中一切皆对象,出现NPE(NullPointException)则是致命性的问题。所以在Kotlin接着这两个操作符:判空操作符“?”强校验“!!”操作符实现预先判空处理机制。

7.1、使用 “?” 在预定义时判断是否能为null

var a: String = "abc"a = null // 编译错误/*如果要允许为null,我们可以声明一个变量为可空字符串,需要在定义的类型后面紧跟一个问号 “?”*/var b: String? = "abc"b = null // 这样编译没问题,对于无法容纳null的类型,我们可以放心的对它的属性进行调用。var a: String = "abc"var aLength = a.length // 放心调用,a肯定不会为null,但不能够对b字符串进行操作,对于可能为空的类型进行操作,我们就必须判空。

7.2、”?” 在使用的时候进行判空

在Kotlin语言中判断一个对象是否为空有两种方式,第一种就是如同Java语言一样,使用if-else进行判空;另一中就还是使用操作符 “?” 进行判断。

// 在Java语言中我们使用的判空方法。if (b != null && b.length > 0) {    println("String of length ${b.length}")} else {    println("Empty string")}// Kotlin,可空类型的判断println("String of length ${b?.length}")

7.3、!! 操作符进行安全类型判断

有些情况NPE对我们来说还是有一定意义的,我们必须catch住此异常。而Kotlin中的又有空安全的机制存在,我们就必须对null进行强校验。

var a : String? = null // 必须是可空类型,不然强校验没有意义val lenC = a!!.length // Erro这样做就会报错

如果希望强校验希望系统抛出一个NPE,那么必须让定义的变量可容纳null,不然强校验就失去意义了。
- 安全的类型转换
若对象不是目标类型,那么常规类型转换可能会导致 ClassCastException。可以借助强校验来进行安全的类型转换,如果尝试转换不成功则返回 null

val aInt: Int? = a as? Int
  • 可空类型的集合
    若你有一个可空类型元素的集合,并且想要过滤非空元素,你可以使用 filterNotNull 方法来实现。
val nullableList: List<Int?> = listOf(1, 2, null, 4)val intList: List<Int> = nullableList.filterNotNull()

8、Elvis 操作符“?:”

Elvis操作符类似Java语言中的三目表达式,Elvis操作符的语法如下:

<结果> = <表达式1> ?: <表达式2>

如果表达式1为null,则返回表达式2的内容,否则返回表达式1(当且仅当左侧表达式1为空时,才会对右侧表达式求值)。

// Elvis操作符获取b字符串的长度,如果b为null则返回-1val lenB = b?.length ?: -1// 等同于逻辑val lenA: Int = if (b != null) {    b.length} else {    -1}

小结

Kotlin和其他程序语言差不多,拥有五种基本数据类型数字字符布尔数组字符串类型,需要注意的是字符串和数组与Java中的区别,这篇文章就到这了,主要就是结合官方的文档和自己的理解重新整理下。官方文档阅读,下一篇开始进入程序的结构的学习。