val
phoneNumber
=
137_6730_5920
L
val
argb
=
0
xFF_00_EF_35
val
bytes
=
0
b
11000011_00100100
复制代码
数值比较与装箱
因为数据类型是类,所以存在两种比较方式:
===
:用来比较两个在内存地址上是否相等
==
:用来比较两个数值是否相等
例子 1:
val a1 = 2000
val a2 = 2000
fun main() {
println("a1 == a2:${a1 == a2}")
println("a1 === a2:${a1 === a2}")
a1 == a2:true
a1 === a2:true
复制代码
在例子 1 中 a1 和 a2 都是指向一个相同的数值常量,这个常亮在内存中只有一个,因此
===
的结果也为 true。
例子 2:
val a1 = 2000
val a2 :Int? = a1
val a3 :Int? = a1
fun main() {
println("a2 == a3:${a2 == a3}")
println("a2 === a3:${a2 === a3}")
a2 == a3:true
a2 === a3:false
复制代码
这里涉及到装箱的内容,我们知道 Java 中从基本数据类型到对应的封装类被称为装箱,从封装类到基本数据类型的过程为拆箱。
而在 Kotlin 中,存在装箱过程,没有拆箱过程,装箱操作出现在有
Int?
等
可空数值类型
的情况下,装箱过程不会改变数值。
上面的例子中,对象 a2,a3 是 Int? 类型,在赋值过程中触发装箱,因此 a2,a3 是两个不同的对象,在内存中地址不同,
===
的结果为 false,但它们的数值是相同的,
==
的结果为 true。
例子 3:
val a1 = 2000
val a2 :Int = a1
val a3 :Int = a1
fun main() {
println("a2 == a3:${a2 == a3}")
println("a2 === a3:${a2 === a3}")
a2 == a3:true
a2 === a3:true
复制代码
再来看例子 3,和例子 2 不一样的地方在于 a2,a3 的类型是 Int,是不可为空的,所以不会触发装箱操作,所以 a2,a3 指向同一个内存地址,
===
的结果为 true。
例子 4:
val a1 = 2
val a2 :Int? = a1
val a3 :Int? = a1
fun main() {
println("a2 == a3:${a2 == a3}")
println("a2 === a3:${a2 === a3}")
a2 == a3:true
a2 === a3:true
复制代码
例子 4 和例子 2 的区别就在于 a1 的值不同,例子 2 中是 2000,例子 4 中是 2。但是就出现了不同的结果,这是因为,在编译成字节码时,
val a2 :Int? = a1
对应的字节码是
Integer a2 = Integer.valueOf(a1);
,而在 Integer 类中对
-128~127
这个范围内的数字进行了缓存,在这范围内的相同数值的 Integer 类型变量指向同一个对象,所以内存地址也是相同的,
===
结果为 true。
详细的可以看这两篇文章了解:
Kotlin基本类型自动装箱的一点问题
Java 笔试面试(4)基本数据类型与运算
因为数据类型都是类,一个类型不是另一个类型的子类型,因此小范围的类型不能直接隐式转换成大范围的类型。需要使用提供的函数进行显式转换。
toByte() - 转换成字节型
toShort() - 转换成短整型
toInt() - 转换成整型
toLong() - 转换成长整型
toFloat() - 转换成浮点型
toDouble() - 转换成双精度浮点型
toChar() - 转换成字符类型
toString() - 转换成字符串类型
在某些情况下也有自动隐式转换,前提是可以推测出正确的类型并且进行了运算符重载。
val a = 1L + 3
// Long + Int => Long
复制代码
位运算
对 Int 和 Long 类型,可以使用位运算符:
shl(bits) – 左移位 (等价于Java里的 <<)
shr(bits) – 右移位 (等价于Java里的 >>)
ushr(bits) – 无符号右移位 (等价于Java里的 >>>)
and(bits) – 与
or(bits) – 或
xor(bits) – 异或
inv() – 反向
详细了解可以看这篇文章:
Kotlin 位运算基础
布尔类型用
Boolean
表示,值为 true 或 false。如果需要可空布尔类型(Boolean?)会被装箱。
Kotlin 中逻辑操作符和 Java 中是一样的。
&& :短路逻辑与
|| :短路逻辑或
Kotlin字符类型用
Char
(大写),要注意的是:
在 Java 中 char 是 int 的一部分,可以直接隐式转换成 int,在 Kotlin 中 Char 不再是 Int 的一部分了,而是一个单独的数据类型,不可以直接转换。
可以通过
toInt()
方法转化成 Int。
fun main() {
val char = 'B'
if(char.toInt() == 65){
println("char is A")
复制代码
字符串类型
Kotlin 中
String
表示字符串,和 Java 一样是不可变的。在 Kotlin 中,可以通过数组下标的方式(
string[index]
)来取字符,也可以使用
in
关键字来遍历整个字符串。
例子 5:
fun main() {
val str: String = "hello"
println("内容:$str")
println("第一个字符是:${str[0]}")
println("第二个字符是:${str.get(1)}")
for (s in str){
println(s)
内容:hello
第一个字符是:h
第二个字符是:e
复制代码
Kotlin 支持多行字符串,用
""" """
表示。
fun main() {
val str: String = """
three
println("内容:$str")
//运行结果
three
复制代码
字符串模板
例子 5 的代码中已经有了字符串模板的使用,直接看即可。Kotlin 中可以在字符串使用
$变量名
或者
${表达式}
的形式格式化字符串,有效代替 Java 中用
+
来拼接字符串。
数组类型用
Array<T>
表示,T 是类型。同样可以用
[index]
下标的方式来读写数组相应位置的值。
数组有三种创建方式:
arrayOf() 方法,参数是可变长的泛型对象
val a = arrayOf(1, 2, 3)
val b = arrayOf("one", "two", "three")
arrayOfNulls,可以创建一个指定类型的初始值全为空的数组,参数是数组长度。
fun main() {
val arr = arrayOfNulls<String>(3)
for(a in arr){
print("$a ")
arr[0] = "one"
arr[1] = "two"
arr[2] = "three"
println()
for(a in arr){
print("$a ")
null null null
one two three
工厂函数:Array(size, {i -> (包含 i 的表达式)})
工厂函数是创建一个长度为 size 的数组,这个数组下标从 0 开始,下标所对应的值是表达式的值。
举一个比较简单的例子,便于理解。
fun main() {
val arr = Array(3, {i -> i * 2 })
for(a in arr){
print("$a ")
0 2 4
复制代码
Kotlin 中还有 ByteArray、ShortArray、IntArray 等类用来表示各个类型的数组,这些类省去了装箱操作,效率更高,使用方式和 Array 一样。
ByteArray - 表示字节型数组
ShortArray - 表示短整型数组
IntArray - 表示整型数组
LongArray - 表示长整型数组
BooleanArray - 表示布尔型数组
CharArray - 表示字符型数组
FloatArray - 表示浮点型数组
DoubleArray - 表示双精度浮点型数组
关于 Kotlin 中的数据类型就写到这里,下一篇是 Kotlin 的分支和循环,以及一些常用关键字的介绍。
Kotlin 基本数据类型
Kotlin——初级篇(三):数据类型详解
Kotlin基本类型自动装箱的一点问题
Java 笔试面试(4)基本数据类型与运算
Kotlin位运算基础