标签搜索

Kotlin基础

Pop.Kite
2021-11-20 / 0 评论 / 199 阅读 / 正在检测是否收录...

基本类型

数字类型

整数型

Kotlin 提供了一组表示数字的内置类型。 对于整数,有四种不同大小的类型,因此值的范围也不同
整数型.png

无符号整型

对于声明无符号的变量,在定义时需要在字面值后缀 u,类似Float或者Long
无符整数型.png

浮点型

对于实数,Kotlin 提供了浮点类型 Float 与 Double 类型。 根据 IEEE 754 标准, 两种浮点类型的十进制位数(即可以存储多少位十进制数)不同。 Float 反映了 IEEE 754 单精度,而 Double 提供了双精度,默认的浮点数是Double类型,声明Float类型的变量需要后缀f浮点型.png

字面常量

Kotlin中的常量可以表示十进制、十六进制和二进制数字。在定义常量时,我们可以使用下划线,让字面值更容易阅读,如下程序会输出 oneMillion is 1000000 :

fun main() {
    val oneMillion = 1_000_000
    println("oneMillion is $oneMillion ")
}

类型转换

kolin不提供类型的隐式转换,因为Koltin中的基本数据类型相当于Java中已经装箱的基本类型,由于不同的表示方式,较小的类型并非较大类型的子类,或者通俗的说Double和Float之间并没有继承的关系,Float类型想要转换成Double并不能通过Java中的隐式转换。不过Kotlin给我们提供了显示转换的方法,所有的基本类型都能够通过这些方法转化为其他类型:

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

    位运算

    Koltin对于Int和Long 类型的整数提供了位运算的操作,可以直接将该类型的数字在二进制级别进行操作,如下程序会输出 x is 1044484 :

    fun main() {

     val x = (1 shl 2) or 0x000FF000
     println("x is $x ")

    }

上述程序中, 1 shl 2 是将 1 作为一个有符号数向左移两位,然后与 0x000FF000 按位或。
其他的位运算如下:

  • shl(bits)– 有符号左移
  • shr(bits) – 有符号右移
  • ushr(bits) – 无符号右移
  • and(bits) – 位与
  • or(bits) – 位或
  • xor(bits) – 位异或
  • inv() – 位非

    布尔类型

    Boolean类型的值有两个:true 和 false;但是Boolean?会提供Null值。
    布尔操作 包括以下三种:

  • || 逻辑或
  • && 逻辑与
  • ! 逻辑非

    字符类型

    Char表示字符类型,字符字面值用单引号括起来表示。
    转义字符以 \开始,支持的转义序列有下面几个:

  • \t、 \b、\n、\r、\'、\"、\ 与 $。

字符串类型

Kotlin 中字符串用 String 类型表示。字符串字面值用双引号括起来表示。

字符串模板

字符串字面值可以包含模板表达式(一些小段代码),会求值并把结果合并到字符串中。 模板表达式以$开头,直接后缀一个变量或用花括号括起来的表达式,如下程序会输出 abc.length is 3 :

fun main() {
    val s = "abc"
    println("$s.length is ${s.length}")
}

数组

数组在 Kotlin 中使用 Array 类来表示。可以使用函数 arrayOf() 来创建一个数组并传递元素值给它,比如 arrayOf(1, 2, 3) 创建了数组[1, 2, 3]。 也可以使用 arrayOfNulls() 创建一个指定大小的、所有元素都为空的数组。
另一个选项是用接受数组大小以及一个函数参数的 Array 构造函数,用作参数的函数能够返回给定索引的元素,下面的代码中创建了一个名为asc的数组并初始化为 ["0", "1", "4", "9", "16"]:

fun main() {
    val asc = Array(5) { i -> (i * i).toString() }
    asc.forEach { println(it) }
}

Kotlin 也有无装箱开销的类来表示原生类型数组: ByteArray、 ShortArray、IntArray 等等。这些类与 Array 并没有继承关系,但是它们有同样的方法属性集。它们也都有相应的工厂方法:

// 大小为 5、值为 [0, 0, 0, 0, 0] 的整型数组
val arr = IntArray(5)

// 例如:用常量初始化数组中的值
// 大小为 5、值为 [42, 42, 42, 42, 42] 的整型数组
val arr = IntArray(5) { 42 }

// 例如:使用 lambda 表达式初始化数组中的值
// 大小为 5、值为 [0, 1, 2, 3, 4] 的整型数组(值初始化为其索引值)
var arr = IntArray(5) { it }


属性

类中的成员变量,可以称其属性。kotlin中的属性默认访问权限是public,可以使用val、var和lateinit声明属性。

  • val :val用于声明只读的属性,只读属性不允许被setter。
  • var:var用于声明可读写的属性。
  • lateinit:声明改变量应该延迟初始化。可以使用 .isInitialized判断是否完成初始化。

    声明属性

    声明一个属性的完整语法如下:

    var : < PropertyType>

     [<getter>]
     [<setter>]
    

其中,initializer、getter和setter都是可选的,若其类型能够被自动推导,则其类型也可以省略。

var index:Int = 1
val index_not_inferred_type = 1

读取属性

如果属性的访问权限为public,则其默认的getter和setter方法也是公开的,但我们也可以自定义其getter和setter方法,这让我们可以直接实现需要计算的属性,如下代码运行后会输出 12:

class Rectangle(val width:Int,val height:Int){
    val area:Int
        get() = this.width * this.height
}
fun main(args : Array<String>){
    val demo = Rectangle(3,4)
    println(demo.area)
}

同样的,如果可以推断出计算属性的类型,我们也可以省略(但是良好的编码习惯是指定类型)。

写入属性

我们也可以自定义属性的setter方法,如下代码运行后会输出 value is abc:

class StringPresent(){
    var stringPresention:String? = null
        set(value){
            println("value is $value")
        }
}

fun main(args : Array<String>){
        val demo = StringPresent()
        demo.stringPresention = "abc"
}

幕后字段

一个属性的幕后字段只能在当前属性的getter和setter中被访问。

class Person {
    var name = ""
        set(value) { 
            this.name = value
        }
}

以上代码中,我们会认为在setter方法中将value赋给name。实则编译期间会栈溢出。将其转换为Java代码,我们可以发现setter被循环调用,自然会出现栈溢出。

public final class Person { 
    @NotNull 
    private String name = "Paul"; 
    @NotNull public final String getName() { 
        return this.name; 
    } 
    public final void setName(@NotNull String value) { 
        this.setName(value); 
    } 
}

在kotlin中使用幕后字段field完成以上的操作,我们修改上述代码如下:
class Person {
    var name = ""
        set(value) { 
            field= value
        }
}

其实上述声明就是默认的setter 方法。使用幕后字段,我们可以根据条件调整属性的值,如下代码运行后会输出 10:

class Person(){
    var age:Int= 0
        set(value) {
            if(value > 0){
                field = value 
            }
        }
}

fun main(args : Array<String>){
    val demo = Person()
    demo.age = 10
    demo.age = -1
    println(demo.age)
}

幕后属性

当有一个属性,我们需要它对外表现为只读、对内则是可读写的,这种属性称之为幕后属性。如下:

class Person(){
    private var _money:Double = 1000.00
    public val money:Double
        get(){
            return _money
        }
}

fun main(args : Array<String>){
    val demo = Person()
    //demo.money = 100
    println(demo.money)
}

上述代码中,在外部,我们通过属性money读取_money的值,但是不能设置_money的值,属性_money只能在内部被读写 ,则_money这个属性我们称之为幕后属性。

参考链接

字面量,常量和变量之间的区别? - 简书 (jianshu.com)
基本语法 · Kotlin 官方文档 中文版 (kotlincn.net)
Kotlin 什么是幕后字段? - 简书 (jianshu.com)
Kotlin 在线工具 | 菜鸟工具 (runoob.com)
Kotlin - iKotliner的学习笔记

0

评论 (0)

取消