【Kotlin】基础变量、集合和安全操作符

这篇具有很好参考价值的文章主要介绍了【Kotlin】基础变量、集合和安全操作符。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

在Kotlin中,所有东西都是对象,在这个意义上讲我们可以在任何变量上调用成员函数和属性。
一些java中的基本数据类型可以有特殊的内部表示——例如,数字(int)、字符和布尔值可以在运行时表示为原生类型值

数字

Kotlin处理数字在某种程度上接近Java,但是并不完全相同。例如,对于数字没有隐式拓宽转换(如Java中int可以隐式转换为long), 另外有些情况的字面值略有不同。

Kotlin提供了如下的内置类型来表示:

Byte(字节):1字节
Short(短整型):2字节
Int(整型):4字节
Long(长整型):8字节
Float(单精度浮点型):4字节
Double(双精度浮点型):8字节
Boolean(布尔型):1字节
Char(字符型):2字节

注意:在Kotlin中字符不是数字,字符用Char类型表示。它们不能直接当作数字(可以用char.code表示出对应编码)

  val char = 'c'
    print(char.code)
    //99

字面常量

可以使用下划线使数字常量更易读,并且不影响赋值

val int = 1_0000_0000
print(int / 10000)
//10000

还可以:

val LongNumber = 999_99_9999L
val hexBytes = 0xFF_EC_DE_5E
val bytes = 0b11010010_01101001_10010100_10010010

显式转换

由于不同的表示方式,较小类型并不是较大类型的子类型。这代表他们不能进行直接的隐式转换:

【Kotlin】基础变量、集合和安全操作符,kotlin,kotlin,开发语言,android

我们可以显式转换来拓宽数字

fun main(){
    val int = 1_0000_0000
    val long: Long = int.toLong()
}

数值类型转换背后

var x = 5 // 这行代码创建了一个Int类型的变量x以及一个Int类型值为5的对象。x保存了该对象的引用
var z : Long = x.toLong() // 这行代码创建了一个新的Long变量z。x对象的toLong()函数被调用并且创建了一个值为5的Long对象,该Long对象的引用被存储在z中

如果该数值超出了新对象所能存储的范围该怎么办?
就像一大杯水装进一个小杯,有些会溢出

如果Long的值超出了Int能容纳的范围,那么编译器将会舍弃超出的部分,会得到一个奇怪(仍可计算)的数值。例如:

var x = 1234567890123
var y: Int = x.toInt()
println(y) // 1912276171

(C语言初学者应该很熟悉的问题)

位运算符

(只用于Int和Long。Kotlin的特性:可以重写操作符函数的逻辑):

shl(bits) – 有符号左移 (Java 的 <<)
shr(bits) – 有符号右移 (Java 的 >>)
ushr(bits) – 无符号右移 (Java 的 >>>)
and(bits) – 位与
or(bits) – 位或
xor(bits) – 位异或
inv() – 位非
区间实例以及区间检测:a..b、 x in a..b、 x !in a..b

字符串

字符串的元素——字符(Char)可以使用索引运算符访问:str[i]。可以用for循环迭代字符串:

for (c in str) {
    println(c)
}

当你使用双引号(“)表示字符串时,它只能包含单行文本。
而当你使用三个双引号(”“”)表示字符串时,它可以包含多行文本
转义采用传统的反斜杠方式。
原生字符串 使用三个引号"""分界符括起来,内部没有转义并且可以包含换行和任何其他字符:

val text = """
    for (c in "foo")
        print(c)
"""

字符串模板

字符串可以包含模板表达式,即一些小段代码,会求值并把结果合并到字符串中。模板表达式以美元符$开头再加上变量的名字。

val i = 10
val s = "i = $i" // 求值结果为 "i = 10"

字符串判等
Kotlin中的判等性主要有两种类型:

  • 结构相等。通过操作符==来判断两个对象的内容是否相等。
  • 引用相等。引用相等由双等号以及其否定形式!= = =操作判断。a = = = b当且仅当a和b指向同一个对象时求值为true。如果比较的是运行时的原始类型,比如Int,那么’= = =判断的效果也等价于’=='。
var a = "hello"
var b = "hello"
var c = "Kotlin"
var d = "Kot"
var e = "lin"
var f = d + e
a == b // true
a === b // true
c == f // true
c === f // false

结构相等由= =以及其否定形式!= =操作判断。
那么a = = b这样的表达式会被翻译为 a?.equals(b) ?: (b === null) 也就是说如果a不是null则调用equals(Any?)函数,否则即a是null检查b是否与null引用相等。
(精妙!)
好多等号一直显示高亮

修饰符

注意,在kotlin中默认的修饰符是public

  • private 所以如果我们给一个类声明为private, 我们就不能在定义这个类之外的文件中使用它。 另一方面,如果我们在一个类里面使用了private修饰符,那访问权限就被限制在这个类里面了。甚至是继承这个类的子类也不能使用它。
  • protected 在Java中是包、类及子类可访问,而在Kotlin中只允许类及子类。
  • internal 它与Java的default有点像但也有所区别。如果是一个定义为internal的包成员的话,对所在的整个module可见。如果它是一个其它领域的成员,它就需要依赖那个领域的可见性了。 比如如果写了一个private类,那么它的internal修饰的函数的可见性就会限制与它所在的这个类的可见性。
  • public 这是最没有限制的修饰符。这是默认的修饰符,成员在任何地方被修饰为public,很明显它只限制于它的领域。

数组

和java不同的是,新建一个数组用类Array实现,并且还有一个size属性及get和set,万物皆对象,由于kotlin使用[]重载了get和set方法,所以我们可以通过下标很方便的获取或者 设置数组对应位置的值。 Kotlin标准库提供了arrayOf()创建数组和xxArrayOf创建特定类型数组

val myArray = arrayOf(1, 2, 3)

还有:

val nums = arrayOf(1, 2, 3)
val numbers = intArrayOf(10, 20, 30)
//intArrayOf 新建int类型数组
val array1 = Array(10, { k -> k * k })
//可用表达式
val emptyArray = emptyArray<String>()
//括号内可以填参数,表示新建数组的大小

和Java不一样的,Kotlin的数组是容器类,提供了ByteArray,CharArray,ShortArray,IntArray,LongArray,BooleanArray,FloatArrayDoubleArray
那么以下两个有什么区别呢?

val arrayA = arrayOf(1, 2, 3)
val arrayB = intArrayOf(1, 2, 3)

当我们显式指明数据类型后:

val arrayA: Array<Int> = arrayOf(1, 2, 3)
val arrayB: IntArray = intArrayOf(1, 2, 3)

区别注意一下,arrayOf() 是Kotlin自带的,很便携,可以进行自判断类型生成对应的Array并填写泛型类。
但是Array是会使用装箱技术。它使用对象引用来存储每个整数(或其他基本数据类型),因此它的内存占用比较大。而IntArray由于不需要装箱和拆箱的过程,IntArray拥有更好的性能和更高的效率。但是也有一定的缺点,他比Array的api要少…

集合(Kotlin自带)

Kotlin有三个主要的集合类型(List、Set和Map),也可以分为可变集合和不可变集合//反正用得不多
简单的List、Set和Map是不可变的,这意味着集合被初始化后不能再添加或移除元素。如果想要添加或移除元素,Kotlin提供了可变的子类型作为替代方案:MutableList、MutableSet和MutableMap。因此,如果想要利用List的所有优势,并希望能够更新其内容,请使用MutableList。
Kotlin的List<out T>类型是一个提供只读操作如size、get等的接口。和Java类似,它继承自Collection<T>进而继承自Iterable<T>。 改变list的方法是由MutableList<T>加入的,且适用于SetMap

可变集合,顾名思义,就是可以改变的集合。可变集合都会有一个修饰前缀“Mutable”,比如MutableList。这里的改变是指改变集合中的元素,比如以下可变集合:

val list = mutableListOf(1, 2, 3, 4, 5)
list[0] = 0 // 变成[0, 2, 3, 4, 5]

Kotlin没有专门的语法结构创建list或set。要用标准库的方法如listOf()、mutableListOf()、setOf()、mutableSetOf()。 创建map可以用mapOf(a to b, c to d)。
最主要可以用 map[key] = value 我很喜欢这样用

var list = listOf(“a”, “b”, “c”)
for(c in list) {
println©
}

fun main() {
    var map = TreeMap<String, String>()
    map["0"] = "0 haha"
    map["1"] = "1 haha"
    map["2"] = "2 haha"
    println(map["1"])
}
val numbers: MutableList<Int> = mutableListOf(1, 2, 3)
val readOnlyView: List<Int> = numbers
println(numbers)        // "[1, 2, 3]"
numbers.add(4)
println(readOnlyView)   // "[1, 2, 3, 4]"
readOnlyView.clear()    // -> 不能编译
val strings = hashSetOf("a", "b", "c", "c")

Kotlin中提供了很多操作结合的函数,例如:

val newList = list.map{it * 2} // 对集合遍历,在遍历过程中,给每个元素都乘以2,得到一个新的集合
val mStudents = students.filter{it.sex == "m"} // 筛选出性别为男的学生
val scoreTotal = students.sumBy{it.score} // 拥挤和中的sumby实现求和

通过序列提高效率

因为filter方法和map方法都会返回一个新的集合,也就是说会产生两个临时集合(跟当初java:String一样),因为list会先调用filter方法,然后产生的集合会再次调用map方法。如果list中的元素非常多,这将会是一笔不小的开销。为了解决这一问题,序列(Sequence)就出现了。(Builder?)

list.asSequence().filter {it > 2}.map {it * 2}.toList()
  • 首先通过asSequence方法将一个列表转换为序列,然后在这个序列上进行相应的操作,最后通过toList方法将序列转为列表。将list转换为序列,在很大程度上就提高了上面操作集合的效率。

因为在使用序列的时候filter方法和map方法的操作都没有创建额外的集合,这样当集合中的元素数量巨大的时候,就减少了大部分开销。

  • 在Kotlin中,序列中元素的求值是惰性的,这就意味着在利用序列进行链式求值的时候,不需要像操作普通集合那样,每进行一次求值操作,就产生一个新的集合保存中间数据。

惰性求值

在编程语言理论中,惰性求值表示一种在需要时才进行求值的计算方式。 在使用惰性求值的时候,表达式不在它被绑定到变量之后就立即求值,而是在该值被取用时才去求值。 通过这种方式,不仅能得到性能上的提升,还有一个重要的好处就是它可以构造出一个无限的数据类型。

序列的操作方式

list.asSequence().filter {it > 2}.map {it * 2}.toList()

序列总共执行了两类操作分别是:

  • filter{it > 2}.map{it * 2}:filter和map的操作返回的都是序列,我们将这类操作称为中间操作。
  • toList():这一类操作将序列转换为List,我们将这类操作称为末端操作。

Kotlin中序列的操作就分为:

中间操作
  • 中间操作都是采用惰性求值的,例如:
list.asSequence().filter {
    println("filter($it)")
}.map {
    println("map($it)")
}

上面操作中的println方法没有执行,这说明filter和map方法的执行被延迟了,正所谓惰性求值。惰性求值仅仅在该值被需要的时候才会真正去求值。 那么怎么去触发这个”被需要“的状态?即——末端操作

末端操作
  • 末端操作就是一个返回结果的操作,它的返回值不能是序列,必须是一个明确的结果, 比如列表、数字、对象等表意明确的结果。
  • 末端操作一般都放在链式操作的末尾, 在执行末端操作的时候,会去触发中间操作的延迟计算,也就是将”被需要“这个状态被激活了
list.asSequence().filter {
    println("filter($it)")
    it > 2
}.map {
    println("map($it)")
    it * 2
}.toList()
// 输出↓
filter(1)
filter(2)
filter(3)
map(3)
filter(4)
map(4)
filter(5)
map(5)
[6, 8, 10]

可以看到,所有的中间操作都被执行了。从上面执行打印的结果我们发现,它的执行顺序与我们预想的不一样。

  • 普通集合在进行链式操作的时候会先在list上调用filter,然后产生一个结果列表,接下来map就在这个结果列表上进行操作。
  • 而序列则不一样,序列在执行链式操作的时候,会将所有的操作都应用在一个元素,也就是说,第一个元素执行完所有的操作之后,第二个元素再去执行所有的操作,以此类推。

可null类型

因为在Kotlin中一切都是对象,一切都是可null的。这就会防止出现NPE异常。当某个变量的值可以为null的时候,必须在声明处的类型后添加?来标识该引用可为空。 Kotlin通过?将是否允许为空分割开来,甚至Any也分可空和不可空。

var value1: String
value1 = null        // 编译错误 Null can not be a value of a non-null type String
var value2 : String?
value2 = null       // 编译通过

在对可空变量进行操作时,如果变量是可能为空的,那么将不能直接调用,否则将会报错。

安全调用操作符 ?.

当你对一个可空类型的变量进行操作时,如果直接调用方法或访问属性,可能会导致空指针异常,那么此时可以使用 ?.

val length = name?.length

如果name不是null,length将返回name的长度;如果name是null,length将直接返回null,而不会抛出异常。

操作符 ?:

该操作符允许我们为可能为null的表达式提供一个默认值。

val length = name?.length ?: 0

在这个例子中,如果name不为null,length将返回其长度;如果name为null,length将返回0。

非空断言操作符 !!

当你确定一个变量绝对不为空时,你可以使用!!操作符,这将告诉编译器说,我已经排除了null值的情况。但是,如果该变量为null,还是会抛出空指针异常。

val length = name!!.length

请谨慎使用!!操作符,因为它会忽略Kotlin中对null安全性的所有保护措施。

使用类型检测及自动类型转换

is运算符检测一个表达式是否某类型的一个实例,如同Java的instanceof。 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,在大多数情况下,is操作符会进行智能转换。表示编译器将变量当作与其声明的类型不同的类型,而智能转换是说编译器替你自动地进行转换。 无需显式转换:

fun getStringLength(obj: Any): Int? {
    if (obj !is String) return null
    // obj 在这一分支自动转换为 String,这是因为Kotlin的编译器帮我们做了转换
    // 这称为Kotlin中的智能转换(Smart Casts)。官方文档中这样介绍: 当且仅当Kotlin的编译器
    // 确定在类型检查后该变量不会再改变,才会产生Smart Casts。
    return obj.length
}

只要编译器能够保证在介于判断对象类型和被使用之间不能修改变量,is操作符就会进行智能转换。

例如,在上面的代码中,编译器知道在介于调用is操作符和调用String的某个方法之间,item变量不能被赋予另一类型的引用。但是在一些特殊情况下,智能转换不会生效。例如,is操作符不会对类中的var属性进行智能转换,那是因为编译器无法保证该属性是否还会被更改。

安全的类型转换 as?

安全类型转换操作符as?尝试进行类型转换,如果失败了不会抛出异常,而是返回null。

val a: Int? = "123".toIntOrNull()//将字符串"123"转换为整数类型,由于转换成功,所以intValue的值为123。
val b: Int? = "abc" as? Int //将字符串"abc"尝试转换为整数类型,由于转换失败,所以intValueOrNull的值为null。
//a = 123  b = null

返回和跳转

Kotlin有三种结构化跳转表达式,和java差不太多:文章来源地址https://www.toymoban.com/news/detail-764790.html

  • return:默认从最直接包围它的函数或者匿名函数返回。
  • break:终止最直接包围它的循环。
  • continue:继续下一次最直接包围它的循环。
    在Kotlin中任何表达式都可以用标签label来标记。标签的格式为标识符后跟@符号,例如:test@
    要为一个表达式加标签,我们只要在其前加标签即可。
loop@ for (i in 1..100) {
    for (j in 1..100) {
        if (i + j == 100) break@loop//退出指定的循环  C语言的goto?
    }
}

到了这里,关于【Kotlin】基础变量、集合和安全操作符的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • C语言基础之——操作符(上)

    本篇文章,我们将展开讲解C语言中的各种常用操作符,帮助大家更容易的解决一些运算类问题。 这里提醒一下小伙伴们,本章知识会大量涉及到二进制序列,不清楚二进制序列的小伙伴,可以去阅读我的另一篇文章 《数据在内存中的存储》 学习了解。 目录 一.操作符分类

    2024年02月11日
    浏览(43)
  • Kotlin中的集合操作

    Kotlin 在集合操作上提供了一系列的扩展函数,使其变得非常强大且易于使用。以下是一些在Kotlin中常用的集合操作API,以及如何使用它们的示例: 1. Filtering (过滤) ​ 使用 filter 函数来过滤集合中符合条件的元素。 2. Transforming (转换) ​ 使用 map 函数能够将集合中的元素进行

    2024年01月18日
    浏览(45)
  • Kotlin 操作集合的高阶函数

    Kotlin 提供了很多高阶函数用于对集合进行操作和转换。以下是一些常用的高阶函数: forEach{} :对集合中的每个元素执行指定的操作, 无返回 值。 map{} :对集合中的每个元素执行指定的操作, 返回 操作后的 集合 filter{} :对每一个元素进行筛选, 返回 满足条件的元素 集合

    2024年02月06日
    浏览(49)
  • 【Kotlin】Kotlin 与 Java 互操作 ① ( 变量可空性 | Kotlin 类型映射 | Kotlin 访问私有属性 | Java 调用 Kotlin 函数 )

    在 Java 语言 中 , 任何 引用类型变量 都可以为 空 null ; Java 中 八种 基本数据类型 变量 的 默认值 为 0 或 false ; 但是在 Kotlin 语言 中 , 所有的 变量 都是引用类型变量 , 没有基本数据类型 , 默认情况下 所有的变量 都为 非空类型 ; 下面分别定义一个 Java 类 和 Kotlin 脚本 , 在 K

    2024年02月02日
    浏览(64)
  • 【C语言初阶】带你轻松玩转所有常用操作符(1) ——算数操作符,移位操作符,位操作符

    君兮_的个人主页 勤时当勉励 岁月不待人 C/C++ 游戏开发 Hello,这里是君兮_,最近要准备期末复习了,可能更新的就不会那么频繁了,下个星期恢复正常更新。 今天给大家带来的是操作符详解,由于这部分的内容比较多,可能会分成几部分讲,今天带来的是第一部分的内容,废

    2024年02月11日
    浏览(46)
  • 【PostgreSQL】函数与操作符-比较函数和操作符

    PostgreSQL中的比较函数和操作符用于比较两个表达式的值。它们的作用是确定表达式的值是否满足某种条件,例如等于、大于、小于等。 比较函数是一个接受两个参数的函数,返回一个布尔值,表示两个参数是否满足某种条件。例如,equal()函数用于判断两个参数是否相等,

    2024年01月17日
    浏览(53)
  • 初始C语言——详细讲解操作符以及操作符的易错点

     第一章 “C“浒传——初识C语言(更适合初学者体质哦!)  第二章 详细认识分支语句和循环语句以及他们的易错点   第三章 初阶C语言——特别详细地介绍函数  第四章 初始C语言——详细地讲解数组的内容以及易错点  第五章  初始C语言——详细讲解操作符以及操

    2024年02月13日
    浏览(57)
  • 【c语言操作符系列1】^(异或操作符)讲解和多种例题详解

    目录 一、^ 是什么(^称为异或) 二、^的规律(特点) 三、可利用^秒杀的常见例题(重点) 1、消失的数字  2、不一样的人生密码 3、交换两个数(不能创建中间变量) 4、找出只出现一个的两个数字 是一种操作符, 针对二进制异或而言的 ,两个数对应的二进制位相同,异或

    2024年02月16日
    浏览(69)
  • Js中.?和??语法(可选链操作符和双问号操作符)

    Tips:为啥起这么一个标题呢,因为我自己当时看代码,看到这个语法的时候就感觉有些遗忘,但是又不知道他叫做什么名字,所以只能直接搜索.?和??这样搜索,哈哈哈相信不少人可能跟我一样,不知道他叫做什么名字嘿嘿。 可选链 操作符( ?. )允许读取位于连接对象链深

    2024年01月21日
    浏览(46)
  • 【C语言】中的位操作符和移位操作符,原码反码补码以及进制之间的转换

    欢迎大家来到c语言知识小课堂,今天的知识点是操作符和进制 同样都是数字1111,不同进制下数字的大小不同,第二行代表的是其各位数字十进制下的大小,将各位数字的十进制大小相加即1111在这个进制下转化为十进制的大小,从图中我们可以看出来 进制的定义:从右往左

    2024年02月22日
    浏览(52)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包