kotlin基础类型

注释

单行注释和多行注释

kotlin和java一样支持当行(// 注释内容)和多行注释(/* 注释内容 */),不同的是kotlin的多行注释支持嵌套,例如:

private fun testComment(msg: String) {
        //单行注释
        /*多行注释开头
        /*嵌套的注释内容*/
        多行注释结尾*/
        Log.d(TAG, "multilineComment: $msg")
}

文档注释

Kotlin的文档注释和java一样,使用/** 注释内容 */

但android studio的在方法上直接输入“/**”并回车,生成的注释没有参数和返回值,可以安装一个插件BugKotlinDocument解决

变量

分隔符

分号(;)

同一行内只有一条语句,可以不以分号结尾,但同一行内书写多条独立的语句,则前面语句就需要使用分号表示结束,例如:

super.onCreate(savedInstanceState);setContentView(R.layout.activity_main)

Kotlin表达式、调用方法、访问属性可以跨多行,字符串跨多行要以加号连接,例如:

var testStr = "test across " +
        "multiple lines"
//表达式可以跨多行
testStr +=
    " expression"
//调用方法时可以跨多行
var isMethod = testStr
    .startsWith ("method")
//访问属性时也可以跨多行
var field = testStr
    .length

花括号({})

定义代码块,类体部分、枚举、方法体需要放在花括号中定义,条件语句中的条件执行体和循环语句中的循环体通常也放在代码块里

方括号([])

索引运算符,用于访问数组元素、List集合元素和Map集合元素

var array = arrayOf(3, 2, 9, 5)
Log.d(TAG, "onCreate: ${array[2]}")
var list = listOf("a", "b", "c", "d", "e")
Log.d(TAG, "onCreate: ${list[2]}")
var map = mapOf("apple" to 5, "orange" to 8)
Log.d(TAG, "onCreate: ${map["apple"]}")

圆括号(())

定义函数、方法时用圆括号包含所有的形参声明,调用函数时用圆括号传入实参值,优先计算圆括号内的表达式

空格( )

使用空格合理地缩进代码,从而提供更好的可读性

圆点(.)

常用作类、结构体、枚举、实例和它的成员(包括属性和方法)之间的分隔符,表明调用某个类或某个实例的指定成员

标识符规则

标识符是用于给程序中的变量、类、枚举、函数等命名的名字。 标识符的长度没有限制,是区分大小写的

  1. 可以由字符、数字和下画线_组成,但不能以数字开头,此处的字符并不局限于英文字母,可以包含中文字符、日文字符等

  2. 标识符不能是Kotlin的硬关键字,在特定上下文中不能使用软关键字和修饰符关键字,但可以包含关键字

  3. 标识符不能包含空格

  4. 标识符只能包含下画线_,不能包含@、#等特殊

关键字

  1. 硬关键字:无论在什么情况下都不能用作标识符

  2. 软关键字:可以在它们不起作用的上下文中用作标识符

  3. 修饰符关键字:可以在代码中用作标识符

硬关键宇

硬关键宇 作用
as 类型转换或为 import 语句指定别名
as? 类型安全 类型转换运算符
break 中断循环
class 声明类
continue 忽略本次循环剩下的语句,重新开始下一次循环
do 用于 do while 循环
else 在 if 分支中使用
false 在Boolean类型中表示假的直接量
for 用于 for 循环
fun 声 明函数
if 在 if 分支中使用
in 在 for 循环中使用,可作为双目运算符,检查一个值是否处于区间或集合内,也可在 when 表达式中使用,还可用于修饰泛型参数,表明该泛型参数支持逆变
!in 可作为双目运算符 的反义词:!in 也可在 when 表达式中使用
is 用于做类型检查(类似 java的instanceof) 或在 when 表达式中使用
!is is 的反义词
null 空的直接量
object 声明对象表达式或定义命名对象
package 前文件指定包
return 函数的返回
super 引用父类实现的方法或属性,或者在子类构造器中调用父类构造器
this 表当前类的对象或在构造器中调用当前类的其他构造器
throw 抛出异常
true 在 Boolean 类型中表示真的直接量
try 开始异常处理
typealias 定义类型别名
val 声明只读属性或变量
var 声明可变属性或变量
when 用于 when 表达式
while 用于 while 循环或 do while 循环

软关键字

软关键字 作用
by 用于将接口或祖先类的实现代理给其他对象
catch 在异常处理中用于捕捉异常
constructor 声明构造器
delegate 指定该注解修饰委托属性存储其委托实例的字段
dynamic 主要用于在 Kotlin/JavaScript 中引用一个动态类型
field 用于指定该注解修饰属性的幕后字段
file 用于指定该注解修饰该源文件本身
finally 异常处理中的 finally块
get 用于声明属性的getter方法,或者用于指定该注解修饰属性的getter方法
import 导包
init 声明初始化块
param 指定该注解修饰构造器参数
property 指定该注解修饰整个属性(这种目标的注解对 Java 不可见,因为 Java并没有真正的属性)
receiveris 用于指定该注解修饰扩展方法或扩展属性的接收者
set 用于声明属性的 se er 方法,或者用于指定该注解修饰属性的 se er 方法
setparam 用于指定该注解修饰 setter 方法的参数
where 用于为泛型参数增加限制。

修饰符关键宇

修饰符关键宇 作用
abstract 修饰抽象类或抽象成员
annotation 修饰注解类
companion 声明伴生对象
const 声明编译时常量
crossinline 用于禁止在传给内联函数的 Lambd 表达式中执行非局部返回
data 声明数据类
enum 声明枚举
external 声明某个方法不由 Kotlin 实现(与 Java native 相似〉
final 禁止被重写
infix 声明该函数能以双目运算符的格式执行
inline 声明内联函数, Lambda 表达式可在内联函数中执行局部返回
inner 声明内部类,内部类可以访问外部类的实例
internal 表示被修饰的声明只能在当前模块内可见
lateinit 修饰 non-null 属性,用于指定该属性可在构造器以外的地方初始化
noinline 禁止内联函数中个别 Lambda 表达式被内联化
open 用于修饰类,表示该类可派生子类;或者用于修饰成员,表示该成员可以被重写
out 修饰泛型参数,表明该泛型参数支持协变
override 声明重写父类的成员
private private 访问权限
protected protected 访问权限
public public 访问权限
reified 修饰内联函数中的泛型形参,接下来在该函数中就可像使用普通类型样使用该类型参数
sealed 声明密封类
suspend 标识一个函数后 Lambda 表达式可作为暂停
tailrec 用于修饰一个函数可作为尾随递归函数使用
vararg 用于修饰形参,表明该参数是个数可变的形参

声明变量

kotlin是一门强类型的语言,变量必须先声明、后使用,声明变量时必须显式或隐式指定变量的类型,当显式和隐式指定都存在时,类型要保持一致,指定类型的变量也只能接受类型与之匹配的值

声明变量需要使用 var或val ,如下所示:

var | val 变量名[:类型][=初始值]

//通过":类型"的形式显式指定该变量的类型
var gender:String
//为该变量指定初始值,隐式指定变量的类型
val name = "小明"
//显式和隐式指定都存在时,类型要保持一致
var age: Int = 18
//var声明的变量值可变
age = 19
//val声明的变量值不可变,因此这里会编译报错
name = "小张"

其中使用 var 声明的变量是值可变的(可被多次赋值),使用 val 声明的变量是值不可变的(不能被重新赋值),相当于常量,Kotlin 的常量分为两种:

局部范围的常量

允许在声明时不指定初始值,只要在第 次使用之前指定初始值即可

类的常量属性

既可以在声明时指定初始值,也可以在类或结构体的构造器中指定初始值

整型

Kotlin 的整型与 Java 不同, Kotlin 的整型不是基本类型,而是引用类型(大致相当于 Java的包装类)

Kotlin是 null 安全的语言,因此Byte、Short、Int、Long 类型变都不能接受 null 值,如果要存储 null 值,则应该使用 Byte?、Short?、Int?、Long?类型

不带“?”后缀的整型变量将会映射成 Java 的基本类型,带“?”后缀的整型变量将会映射成基本类型的包装类

整型类型

整型类型 所占位数 表数范围
Byte 8位 -128~127
Short 16位 -215~215-1
Int 31位 -231~231-1
Long 64位 -263~263-1

使用“===”比较相等,要求两个变量引用同一个对象

var value1: Int = 200 // value1 的类型是 Java int 类型
var value2: Int = 200 // value2 Java int 类型
Log.d(TAG, "onCreate: ${value1 == value2}") // 基本类型比较,输出 true
var obj1: Int? = 200 // obj1 的类型是 Java Integer 类型
var obj2: Int? = 200 // obj2 的类型是 Java Integer 类型
// 引用类型比较,输出 false,但如果obj1和obj2值都改为小于-128~127之间值相等的整数,则返回true
Log.d(TAG, "onCreate: ${obj1 == obj2}")

由于 Int 型是 Kotlin 最常用的整数类型,因此,如果声明一个常量或变量时没有显式指定数据类型,只是简单地指定了其初始值为整数值,那么 Kotlin 会自动判断该变量的类型为 Int

kotlin 的整数数值表示方式

Kotlin 不支持八进制的整数

  1. 十进制:普通的整数数值就是十进制的整数
  2. 二进制:以 0b或0B 开头的整数数值
  3. 十六进制:以 0x或0X 开头的整数数值,其中 10~15 分别以af(此处的af不区分大小写)来表示
//以0b或0B开头的整数数值是二进制的整数
var binValuel = 0b1010101
var binValue2 = 0B10101110
//以0x或0X开头的整数数值是十六进制的整数
var hexValuel = 0x13
var hexValue2 = 0XaF

kotlin允许为数值(包括浮点型)增加下画线作为分隔符

val value = 1_000_000

浮点型

浮点型数值可以包含小数部分,浮点型比整型的表数范围更大,可以存储比 Long 型更大或更小的数

浮点型类型

浮点型类型 位数 使用情况
Float 32位 精度要求不高时可以使用此种类型
Double 64位 当程序要求存储很大或者高精度的浮点数时使

kotlin 的浮点数表示方式

  1. 十进制数形式:简单的浮点数 例如6.74、530.0、0.54,必须包含 数点,否则会被当成整数类型处理

  2. 科学计数形式:例如5.12e(即 5.12*10^2 ),e不区分大小写

只有浮点型的数值才可以使用科学计数形式表示,例如: 5000 是Int型的值,但 5E3是浮点型的值

如果声明一个常量或变量时没有指定数据类型,只是简单地指定了其初始值为浮点数,那kotlin会自动判断该变量的类型为Double

kotlin 还提供了3个特殊的浮点型数值:正无穷大、负无穷大和非数

例如,使用一个正数除以0.0将得到正无穷大数值,使用一个负数除以0.0将得到负无穷大数值,0.0除以0.0或对负数开方将得到个非数,所有的正无穷大数值都相等 所有的负无穷大数值都相等;而非数不与任何数值相等,甚至和非数自己都不相等

字符型

字符型通常用于表示单个的字符,必须使用单引号(’)括起来,Kotlin使用16 位的 Unicode 字符集作为编码方式,支持各种语言的字符,与Java 不同的是, Kotlin中 Char 型变量不能当成整数值使用

kotlin 的字符表示方式

  1. 通过单个字符来指定字符型值,如'A' 、'c'、'9'等
  2. 通过转义字符表示特殊字符型值,如'\n'、'\t'
  3. 直接使用 Unicode 值来表示字符型值,格式是'\uXXXX',其中 XXXX 代表一个十六进制的整数

数值型之间的类型转换

整型之间的转换

与Java 不同, Katlin 不支持取值范围小的数据类型隐式转换为取值范围大的类型

toByte(): 转换为 Byte 类型

toShort():转换为 Short 类型

tolnt(): 转换为 Int 类型

toLong():转换为 Long 类型

toFloat(): 转换为 Float 类型

toDouble(): 转换为 Double 类型

toChar(): 转换为 Char 类型

取值范围大的变量或表达式强制转换为取值范围小的类型时,可能发生溢出,例如将233 强制转换为 Byte 类型,从而变成了-23,如下图:

image-20211019212702344.png

反码:正数的反码还是等于原码,负数的反码就是他的原码除符号位外,按位取反

补码:正数的补码还是等于原码,负数的补码等于反码+1

Kotlin 缺乏隐式转换,但 Kotlin 在表达式中可以自动转换,这种转换是基于上下文推断出来的,例如:

val byteValue: Byte = 17
val shortValue: Short = 32
val total1 = byteValue + shortValue
//将Byte类型和Short类型相加,不需要对它们进行强制转换,Kotlin将会自动把它们
//提升到 Int 类型之后再进行计算,因此整个表达式计算得到的结果是 Int 类型
Log.d(TAG, "onCreate: ${total1.javaClass}")

val value1 = 89
val value2 = 764
//下面表达式中的 value1 强制转换为 Long 类型,最高等级的操作数是 Long 类型,
//因此整个表达式计算得到的结果也是 Long 类型
val total2 = value1.toLong() + value2.toByte()
Log.d(TAG, "onCreate: ${total2.javaClass}")

Char 型值虽然不能被当成整数进行算术运算,但 Kotlin Char 类型提供了加、减运算支持,其计算规则如下:

Char 型值加、减一个整型值:先将该 Char 型值对应的字符编码进行加、减该整数,然后将计算结果转换为 Char 型值

两个 Char 型值进行相减:Kotlin 将用两个 Char 型值对应的字符编码进行减法运算,最后返回 Int 类型的值。两个 Char 型值不能相加。

var c1 = 'f'
var c2 = 'k'
Log.d(TAG, "onCreate: ${c1 + 4}")//输出j
Log.d(TAG, "onCreate: ${c1 - 4}")//输出b
Log.d(TAG, "onCreate: ${c1 - c2}")//输出-5

当进行类型转换时,应该尽量向表数范围大的数据类型转换,Kotlin 的各种数值型的表数范围由小到大的顺序为 Byte->Short->Int->Long->Float->Double

表达式类型的自动提升

当一个算术表达式中包含多个数值型的值时,整个算术表达式的数据类型将发生自动提升,规则如下:

  1. 所有的 Byte、Short 类型将被提升到 Int 类型
  2. 整个算术表达式的数据类型自动提升到与表达式中最高等级操作数同样的类型

如果表达式中包含了字符串:

//输出字符串Hello!a7
Log.d(TAG, "onCreate: ${"Hello!" + 'a' + 7}")
//输出字符串hHello!
Log.d(TAG, "onCreate: ${'a' + 7 + "Hello!"}")

Boolean 类型

用于表示逻辑上的“真”或“假”,Boolean 类型的值只能是 true或false

null 安全

非空类型和可空类型

var str="dhfjsd"
//由于str转换为Int会失败,会直接挂掉,
//Caused by: java.lang.NumberFormatException: For input string: "dhfjsd"
var num1: Int = str.toInt()
//str转换为Int有可能失败,num有可能没有值,因此不能使用Int来声明num的类型,会编译报错
var num2: Int = str.toIntOrNull()
//正确写法
var num3: Int? = str.toIntOrNull()
//这种写法也正确,编译器会推断出该类型为Int?
var num4 = str.toIntOrNull()

在类型的后面加上?就变成了可空类型

先判断后使用

Kotlin 对可空类型进行了限制 :如果不加任何处理,可空类型不允许直接调用方法、访问属性,但可以先判断该变量不为 null ,然后再调用该变量的方法或属性

//先判断str不为null,然后访length属性
var len = if (str != null) str.length else -1

对于可空的 Boolean 类型而言,它可以接受3个值,即 true、false、 null ,因此对 Boolean?类型变量进行判断时,需要使用 Boolean?变量显式与 true或者false 值进行比较,例如:

var b: Boolean? = null
if ( b == true ) {
    ......
}

如果将 if 分支改为如下形式,编译器会报错,因Kotlin if 条件必须是 Boolean 类型,而 Boolean? 与 Boolean 本质上是两种不同的类型

if ( b ) {
    ......
}

安全调用

使用“?.”进行安全调用,例如:

var str : String? ="dsfdsg"
Log.d(TAG, "onCreate: ${str?.length}") //输出6
str = null
Log.d(TAG, "onCreate: ${str?.length}") //输出null

如果str不为null,调用其length属性并返回,否则返回null

此外,安全调用还可与 let 全局函数结合使用

//定义一个元索可空的数组
val myArr: Array<String?> = arrayOf("fkit", "fkjava ", null, "crazyit")
for (item in myArr) {
    //当 item 不为 null 时才调用 let 函数
    item?.let {
        Log.d(TAG, "onCreate: $item")
    }
}

Elvis 运算

if else 的简化写法

var str: String? = "dsfdsg"
//使用 Elvis 运算符
var len = str?.length ?: -1

“?:”的含义是如果“?:”左边的表达式不为 null ,则返回左边表达式的值,否则返回“?:”右边表达式的值

此外,由于 kotlin的return、throw 都属于表达式,因此它们也都可以用在“?:”运算符的右边,例如:

var len = str?.length ?: throw RuntimeException("str is null")

强制调用

使用“!!.”进行强制调用,即可强制调用可空变量的方法或属性,这样强制调用可能引发空指针异常,例如

//定义一个元索可空的数组
val myArr: Array<String?> = arrayOf("fkit", "fkjava ", null, "crazyit")
for (item in myArr) {
    //当 item 为 null 时会出现空指针异常
    item!!.let {
        Log.d(TAG, "onCreate: $item")
    }
}

字符串

字符串类型

String允许通过形如s[i]的格式来访问字符串指定索引处的字符,也可通过 for循环遍历字符串中的每个字符,例如:

var str: String = "dsfdsg"
Log.d(TAG, "onCreate: ${str[2]}")//输出f
for (c in str) {
    Log.d(TAG, "onCreate: ${c}")
}

字符串有两种字面值:

  1. 转义字符串: 可以包含转义字符
  2. 原始字符串:原始字符串内部没有转义,可以包含换行和任意文本,需要用3个引号引起来,
        //转义字符串
        var str = "fkjava. rq"
        //原始字符串
        val originText = """
            
val myArr: Array<String?> = arrayOf("fkit", "fkjava ", null, "crazyit")
for (item in myArr) {
    //当 item 不为 null 时才调用 let 函数
    item?.let {
        Log.d(TAG, "onCreate: ")
    }
}
        """.trimMargin()
        Log.d(TAG, "onCreate: $originText")

用trimMargin() 方法来去掉原始字符串前面的缩进,默认情况下,使用竖线(|)作为边界符,也就是说所有竖线(|)之前的内容都会被去掉,也可使用其他字符作为边界符, 此时就需要在trimMargin()方法中传入该边界符作为参数

字符串模板

kotlin允许在字符串中嵌入变量或表达式,只要将变量或表达式放入${}中即可,这样kotlin将会把该变量或表达式的值嵌入该字符串中

var str: String = "dsfdsg"
//在字符串模板中嵌入变量
var str1 = "str长度是:${str}"
//在字符串模板中嵌入方法调用
var str2 = "最大值是:${max(5, 28)}"

Katlin 字符串的方法

Kotlin String Java String 并不是同一个类,Kotlin Strin 类提供了更多的方法,

如一系列toXXX()方法将字符串转换成数值,例如:

str.toDouble()
str.toInt()

将字符串首字母大写、小写的方法:

str.capitalize()//大写
str.decapitalize()//小写

返回两个字符串相同的前缀、后缀的方法

str.commonPrefixWith ("crazyjava.org") //前缀
str.commonSuffixWith ("fkit.org") //后缀

Java的String.contains()方法不支持使用正则表达式,但 kotlin的String.contains()方法支持使用正则表达式匹配

var str = "java886"
//判断 str 是否包含3个连续的数字
println(str.contains(Regex("\\d{3}")))

类型别名

Kotlin 提供了 typealias 来定义类型别名,typealias 语句的语法格式为:

typealias 类型别名=已有类型

//为MutableMap<String, MutableList<File>>指定更短的别名:FileTable
typealias FileTable = MutableMap<String, MutableList<File>>

给内部类起别名

class A {
    inner class Inner {}
}
typealias AInner = A.Inner

var aInner = A().AInner()

Java Lambda 表达式的类型是函数式接口,而 kotlin Lambda 表达式的类型直接就是函数类型,因此 kotlin允许为 Lambda 表达式的类型指定别名

//为(T)->Boolean 类型指定别名 Predicate<T>
typealias Predicate<T> = (T) -> Boolean

//使用Predicate<String>定义变量变量,其值是 Lambda 表达式
val p: Predicate<String> = { it.length > 4 }
//为 filter()方法传入p参数,只保留长度大于4的字符串
println(arrayOf("Java", "Objective", "Kotlin").filter(p))
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,491评论 5 459
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,856评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,745评论 0 319
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,196评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,073评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,112评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,531评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,215评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,485评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,578评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,356评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,215评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,583评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,898评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,174评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,497评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,697评论 2 335

推荐阅读更多精彩内容