kotlin 中的数字

以下均来自官方文档:

一、整数类型

1、kotlin中内置的整数类型,有四种不同大小的类型:

类型存储大小(比特数)最小值最大值
Byte8-128127
Short16-3276832767
Int32-2,147,483,648 (-231)2,147,483,647 (231 - 1)
Long64-9,223,372,036,854,775,808 (-263)9,223,372,036,854,775,807 (263 - 1)

注:

当初始化一个没有显示指定类型的变量时,编译器会自动推断为自Int起足以表示该值的最小类型。意思是:如果不超过Int范围,那么类型为Int,如果超过了,那么类型是Long。如果指定值类型为Long类型,请给该值追加后缀L。如果显示的指定类型,会触发编译器检测该值是否超过指定类型的范围。

2、代码演示

// val或var来定义a = 1,打印类型,默认为java的int类型
fun main() {
    val a = 1
    // Kotlin的类型信息在运行时是基于JVM的,所以可以利用Java的反射API来获取类型信息
    println("类型为: ${a.javaClass.simpleName}") // 类型为: int
}

输出结果: 

 

// 下边打印输出类型为long类型,因为类型推断超出Int类型,所以输出long类型
fun main() {
    val a = 10000000000000
    println("类型为: ${a.javaClass.simpleName}") // 类型为: long
}

输出结果: 

显示指定Long类型

// 值后边加上L,来显示指定Long类型,或者 定义Long类型
fun main() {
    val a = 100L
    val b: Long = 100
    println("类型为: ${a.javaClass.simpleName}") // 类型为: long
    println("类型为: ${b.javaClass.simpleName}") // 类型为: long
}

二、浮点类型

1、kotlin中内置的浮点类型:单精度Float与双精度Double类型

这两个类型的大小不同,并为两种不同精度的浮点数提供存储:

类型大小(比特数)有效数字比特数指数比特数十进制位数
Float322486-7
Double64531115-16

可以使用带小数部分的数字初始化Double与Float变量。小数部分与整数部分之间用点 .  分割,对于以小数初始化的变量,编译器会自动推断为Double类型:

fun main() {
    val a = 100.1
    println("类型为: ${a.javaClass.simpleName}") // 类型为: double
}

如果需要将一个值显式指定为Float类型,请添加 f F 后缀。如果值包含多于6到7位十进制数,那么会将其四舍五入:

// 实际测试Float类型多于4到5位十进制数,都会四舍五入,不知为啥!
fun main() {
    val a = 100.31415966 // 默认推断Double类型
    val b = 100.3141596f // 指定Float类型
    println("a为: ${a}") // a为: 100.31415966
    println("b为: ${b}") // b为: 100.31416
}

三、数字的装箱拆箱

1、在jvm平台,数字的存储为原生类型 int、double等。有例外的情况是:当创建可空数字引用如:泛型、Int? ···。在这些场景中,数字会装箱为JAVA类 Integer、Double等。

解释一下:在java世界里,有两种存放数字的方式:
(1)直接存储数字(原生类型):
        就像你在口袋里直接放了几块糖,你知道那是几块,可以直接用。在Java中,intdouble这些就是这种类型的糖,它们直接存数字,速度快,效率高。比如,你有个int num = 5;,这里的num就像你口袋里的5块糖,很直接。
(2)把数字放进盒子中,在存储(装箱类型):
        有时候,你可能想要更灵活一点,比如说,你的糖可能会没有(因为没买或者吃完了),这时候你就需要一个盒子来帮助你表示“有糖”或“没糖”。在Java中,如果你用IntegerDouble这样的类型,就像是给糖准备了个盒子。当你写Integer num = null;或用在泛型、可空类型如Int?时,就相当于,这个盒子里可能有糖(具体的数字),也可能什么都没有(null)。
装箱就是把简单直接的糖(原生类型)包装进一个盒子(变成对象,如Integer),这样可以做更多事情,比如表示“无糖状态”,但相对的,操作起来比直接拿糖要麻烦一点,因为每次要用糖时,都要从盒子里拿出来(拆箱)。
原生类型(如intdouble)直接存储数值,效率高;而像IntegerDouble这样的装箱类型,则是把数值包装成对象,可以表示额外的“无值”状态,但在使用时涉及到自动装箱和拆箱,稍微复杂一些。

2、代码演示

fun main() {
    val a: Int = 100
    // 装箱,赋值为可空的b
    val b: Int? = a
    // 装箱,赋值为可空的c
    val c: Int? = a

    val d: Int = 10000
    // 装箱,赋值为可空的e
    val e: Int? = d
    // 装箱,赋值为可空的f
    val f: Int? = d

    println(b === c) // true
    println(e === f) // false
}

解释:

上边代码演示了装箱(boxing)和常量池(constant pool)的概念,这是理解打印结果差异的关键。
在Kotlin中,当一个原始类型(如Int)被赋值给一个可空类型(如Int?),这个过程被称为装箱,即原始类型值被封装成一个对象。但是,为了优化性能,Kotlin(以及Java)会对特定范围内的Int值(通常是-128到127)使用缓存,这意味着在这个范围内的值在装箱时会复用同一个对象。这就是所谓的享元模式(Flyweight Pattern),可以减少内存使用并提高效率。
分析代码:

  • 对于变量a,它的值是100,处于上述的缓存范围(-128到127)内。所以,当a被装箱赋值给bc时,这两个变量实际上引用的是同一个缓存中的Integer对象。因此,b === c比较的是两个对象的引用是否相同,结果为true,表示它们确实是同一个对象。

  • 变量d的值是10000,超出了常量池的缓存范围。因此,当d被装箱为e和f时,会为每个变量创建一个新的Integer对象,即使它们的值相同。这意味着ef是两个不同的对象,即使它们的数值相等。因此,e=== f比较的是不同对象的引用,结果为false

总结:

打印结果的不同是因为值为100的Int对象在装箱时被缓存并复用,而值为10000的Int对象由于超出缓存范围,每次装箱都会创建新的对象实例。这就解释了为什么第一个比较结果为true而第二个为false

再来看一段代码:

fun main() {
    val a: Int = 10000
    // 装箱,赋值为可空的b
    val b: Int? = a
    // 装箱,赋值为可空的c
    val c: Int? = a

    println(b == c) // true
}

为什么上边代码打印结果为true?

解释:

b == c打印出true的原因在于这里使用的是==操作符来进行比较,而不是===。在Kotlin中,==用于比较两个对象的内容(值)是否相等,而===用于比较两个引用是否指向同一个对象(即它们是否完全相同)。

分析代码:

当比较的是两个装箱的Int?类型变量(bc)时,==操作符会触发自动拆箱(unboxing),并将它们的原始Int值进行比较。在这个例子中,bc虽然是两个不同的对象(因为它们是分别装箱得到的),但它们的内部整数值都是10000,所以b == c的结果为true

总结:

b == c是比较的两个变量的值是否相等,而不是它们是否是同一个对象,所以结果是true

四、类型转换

1、数字类型的互转

  • toByte(): 转Byte类型 
  • toShort(): 转Short类型
  • toInt(): 转Int类型
  • toLong(): 转Long类型
  • toFloat(): 转Float类型
  • toDouble(): 转Double类型
fun main() {
    val a = 1 // 默认会推断为Int类型
    println(a.toByte()) // 1
    println(a.toInt()) // 1
    println(a.toFloat()) // 1.0
    println(a.toDouble()) // 1.0
    println(a.toLong()) // 1
    println(a.toShort()) // 1
}

五、大小比较及区间检测

1、kotlin中大小比较跟java一样

  • 相等性检测:a == b 与 a != b
  • 比较操作符:a < b、 a > b、 a <= b、 a >= b
  • 区间实例以及区间检测:a..b、 x in a..b、 x !in a..b

代码演示(.. 区间):

// a..b 表示从a到b这个区间
fun main() {
    for (i in 1..100){
        println(i) // 会打印1-100 的数字
    }
}

  • 21
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值