Kotlin 之旅2--数据类型

Kotlin的数据类型

Boolean类型

通过下面的代码定义了一个Boolean的变量b:

val b: Boolean = true

Boolean大部分情况下是相当于Java中的boolean,但是有时候会装箱成Java的Boolean,但是这都是由编译器自动决定的,我们不用去理会。(其他类型也如此类推)

Number类型

Kotlin中的数值类型如下所示:

Number类型.png

注意的地方:

  • 可以使用Int.MAX_VALUE等求最值(如此类推)
  • 与Java一样,当类型不明确的时候,可以加L、F来标识;可以使用科学计数法
  • 可以用二进制等进制来表示数值,如:可以用0b00000011表示Int型的3
  • 当数值不正确的时候,例如打印0/0的时候,就会输出NaN(即Not A Number),NaN没有比较的意义。
类型转换

Java中,支持隐式类型转换,例如:

int i = 1;
long l = i;

Kotlin类型转换的时候,不可以隐式转换,必须显式转换,例如:

val i: Int = 1
val l: Long = 1L

fun main(args: Array<String>) {
    //错误
    l = i
    //正确
    l = i.toLong()
}
Kotlin不区分装箱和非装箱类型

在Java中,我们经常需要进行装箱和非装箱,例如:

Integer i1 = new Integer(1);
int i2 = 1;

但是,Kotlin不区分装箱和非装箱类型,编译器会自动帮我们进行转换。

Char类型

Char类型对应的是Java中的Character,占两个字节,表示一个16位的Unicode字符。

val c: Char = '0'
//注意:这里并不是String
val c1: Char = '\u000f'

字符使用单引号''括起来,可以是常见的字符、编码(注意不是String)、转义字符。

Kotlin的转义字符如下:

Kotlin的转义字符.png

String类型

本质就是一串Char类型,用双引号""

下面是字符串的创建方式
val s1: String = "love"
val s2: String = String(charArrayOf('l', 'o', 'v', 'e'))

//获取字符串长度
//s1.length
字符串的比较(注意与Java对比)
//相当于Java的equals
println(s1 == s2)
//相当于Java的==
println(s1 === s2)
字符串模板
//Java中,拼接很麻烦
println("" + a + "+" + b + "=" + (a + b))
//Kotlin中,很方便。类似于PHP
println("$a+$b=${a + b}")
Tips:$符号可以通过转义字符$进行输出
原始字符

原始字符用三引号引起来,字符会原封不动的输出:

    val i: Int = 10000

    val rawStr: String = """
我爱你

    $i

年

    """
    println(rawStr)

空类型安全

先来看看Java代码:

public static void main(String[] args) {
    System.out.println(getName().length());
}

public static String getName() {
    return null;
}

如果getName()方法是别人的库,而且没有源码的话,编译器根本就不知道这里会不会为空,因此这里会有空指针的隐患的。

下面是Kotlin的代码示例:

fun getName(): String {
    return null
}

因此我们就不能返回null了,因此我们可以放心使用getName()的返回值:

fun main(args: Array<String>) {
    println(getName().length) 
}

fun getName(): String {
    return "str"
}
判空的省略版本

你会发现,这样写根本就编译不通过,如果我们确实需要返回null,那么我们需要加上一个问号:

fun getName(): String? {
    return null
}

fun main(args: Array<String>) {

    val name = getName() ?: return

    //上面的写法是相当于:
    //val name = getName()
    //if (name == null) {
    //    return
    //}

    //因为上面已经判断过了,因此可以放心使用了
    println(name.length)
}
如果我们确实代码不为null
val str: String? = "haha"
//如果我们在代码中已经确定不为空指针的话,可以告诉编译器放心编译
println(str!!.length)
安全的调用,可以在对象为空的时候,返回null,而不会触发空指针
val str: String? = null
//这种写法也是可以的
println(str?.length)//实际上打印的是null
//相当于
//if (str == null) {
//    println(null)
//} else {
//    println(str.length)
//}

智能类型转换

Java中,如果对类型进行了判断,还是需要进行转换的:

Parent p = new Child();
if (p instanceof Child) {
    ((Child) p).say();
}

Kotlin中,如果对类型进行了判断,那么不需要进行转换:

val p: Parent = Child()
if (p is Child) {
    //如果Kotlin编译器判断到已经对类型进行了判断
    //那么可以直接调用了
    p.say()
}

安全类型转换

val p: Parent = Parent()
//不安全的类型转换,转换失败会报异常
val c1: Child? = p as Child
//安全的类型转换,转换失败的时候,返回null
val c2: Child? = p as? Child

区间

Kotlin中区间都是ClosedRange的子类,常用的有:

  • IntRange
  • CharRange
  • LongRange
  • ComparableRange

下面先来看看ClosedRange的实现:

public interface ClosedRange<T: Comparable<T>> {
    /**
     * The minimum value in the range.
     */
    public val start: T

    /**
     * The maximum value in the range (inclusive).
     */
    public val endInclusive: T

    /**
     * Checks whether the specified [value] belongs to the range.
     */
    public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive

    /**
     * Checks whether the range is empty.
     */
    public fun isEmpty(): Boolean = start > endInclusive
}

示例代码:

fun main(args: Array<String>) {

    //[0,100]
    val r1: IntRange = 0..100
    //[0,101)相当于[0,100]
    val r2: IntRange = 0 until 101
    //空区间
    val r3: IntRange = 0..-1

    println(r1.start)
    println(r1.endInclusive)

    //是否包含
    println(r1.contains(50))
    println(50 in r2)//运算符重载的方式判断

    println(r3.isEmpty())

    //迭代
    for (i in r1) {
        println("$i,")
    }
}

关于运算符重载,可以先来看看,详细的后面再说:

public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive

数组

示例代码:

//基本数据类型的数组(注意是经过定制的,减去了装箱以及拆箱的开销)
val arr: IntArray = intArrayOf(1, 2, 3, 4, 5, 6, 7)
//没有经过定制的数组
val arr1: Array<Int> = arrayOf(1, 2, 3, 4, 5, 6, 7)
//对象数组
val arrMan: Array<Man> = arrayOf(Man("李"), Man("张"), Man("吴"))

//大小
println(arr.size)

//操作某一个元素
println(arr[0])

//连接成字符串,可以指定分隔符(默认是,)
println(arr.joinToString(","))

//截取,注意传入的是一个区间(注意,字符串也支持这种操作)
arr.slice(1..2)

//遍历
for (i in arr) {
    println(i)
}

如果觉得我的文字对你有所帮助的话,欢迎关注我的公众号:

公众号:Android开发进阶

我的群欢迎大家进来探讨各种技术与非技术的话题,有兴趣的朋友们加我私人微信huannan88,我拉你进群交(♂)流(♀)

推荐阅读更多精彩内容