新手上路,Kotlin学习笔记(五)---Kotlin中的类型系统

         入行没几年的小码农,近期学习Kotlin,做一份笔记记录,此文依据《Kotlin实战》这本书的流程记录,部分示例内容均摘自《Kotlin实战》,记下自己的理解,本篇记录Kotlin中如何解决我们深恶痛绝的空指针问题,和Java对比,基础数据类型和集合的改变。



        Kotlin学习笔记系列

        新手上路,Kotlin学习笔记(一)-- Kotlin入门介绍

        新手上路,Kotlin学习笔记(二)---方法(函数)部分

        新手上路,Kotlin学习笔记(三)---类、对象、接口

        新手上路,Kotlin学习笔记(四)---Lambda表达式在Kotlin中的使用

        新手上路,Kotlin学习笔记(五)---Kotlin中的类型系统

        新手上路,Kotlin学习笔记(六)---运算符重载和其它约定

        新手上路,Kotlin学习笔记(七)---Lambda作为形参和返回值的使用

        新手上路,Kotlin学习笔记(八)---泛型的使用

        新手上路,Kotlin学习笔记(九)---注解和反射



一、可空性

        和Java中到处都有null的场景不同,Kotlin对于null的使用非常谨慎,如果一个对象可以为null,需要特殊的指定,只有在一个类型之后加上问号“?”,这个类型才能存储null对象

    var person : Person? = null //Person? 可以赋值为null
    var person2 : Person = Person() //Person 不能赋值为null
        tips:可空类型(如Person?)即使赋值之后,也不能直接再次赋值给(Person),比如上文中person赋值后,也不能直接执行person2 = person

        (1) 安全调用运算符

        在Java中,当一个类型可能为空的时候,我们通常会先判断if(null != xxx) 然后再去调用对应的方法,写起来很繁琐而在Kotlin中,当一个对象是可空类型时,我们可以使用安全调用运算符来完成空指针的判断操作,使用方式如下

    person?.showName()  //使用?.调用一个方法或者属性,会先判断该对象类型,不为null的时候才会去执行

        在使用安全调用运算符的时候,不为空才会执行,当对象为空时,这个表达式就会返回null,此时,如果我们不期望返回null,在当数据为null的时候,返回某个我们指定的数据该怎么办呢?接下来就该我们的Elvis运算符?:上场了,该运算符的作用就是当运算结果不为空的时候,不做任何改变,当?:前面的结果为空时,将运算符后面的结果返回。

        var index : Int? = null
        var index2 : Int = index ?: 0 //此时 index2结果为0 而不是index的null
        index = 1
        var index3 : Int = index ?: 0 //此时 index不为null index3的结果是1

        前面我们说过,可空类型不能直接赋值给同名的不可空类型,那么当我们需要赋值的时候该怎么办呢?

        (2)安全转换as?

        前面几章我们见过as这个运算符,as可以将一个类型转换为另一个类型,相当于java中 instance of 的作用。这里我们提供了新的使用方式 as?  添加问号之后变为了安全转换,当实际不为空的时候,返回同名的不可空类型,当为空的时候,返回null并不会抛出异常。

        (3)非空断言   !!

        对于一个可空类型,Kotlin还为我们提供了一个简单粗暴的方式将其转换为非空类型,那就是在对象后面加双感叹号"!!",这样编译器就会认为这个对象是非空的,然后进行相关的操作,当然,如果这个对象实际是空的,就会抛出异常退出,所以对于非空断言"!!"应谨慎使用。

            var person : Person? = null //Person? 可以赋值为null
            var person2 : Person = Person() //Person 不能赋值为null
            person2 = person!! //使用非空断言的方式赋值

        (4)let

        Kotlin中提供了一个名为let的方法,这个函数的作用是将调用该方法的对象变为Lambda表达式的参数,当使用安全调用运算符的时候,Lambda里面的参数就是非空的了

    fun printPersonName(person : Person?)
    {
        person?.let { println(it.name) }//it只能转换为Person了,是非空类型
    }

        (5)lastinit

        在Android开发中,我们通常会先声明一个成员变量,此时成员变量的值为null,然后在onCreat方法中去给这个变量进行赋值,如果用Kotlin开发的话,这种情况就需要声明为可空类型,使用的时候,每次都要做非空判断,会非常的不方便。

        对于上面这个场景,我们在Kotlin中可以使用延迟加载的方式,使用lastinit关键字来声明成员变量,这样就允许该变量在以后进行赋值,此变量可以声明为非空类型。

        声明方式如下,lastinit声明的一定是var类型的

    lateinit var str : String

        (6)可空类型的扩展方法

        对于前面学习的扩展方法,对于可空类型同样适用,为可空类型书写扩展方法,可以让我们不进行非空判断的时候也去调用。如Kotlin源码中的这个方法,可空类型也可以直接调用,非常方便

/**
 * Returns `true` if this nullable char sequence is either `null` or empty or consists solely of whitespace characters.
 */
@kotlin.internal.InlineOnly
public inline fun CharSequence?.isNullOrBlank(): Boolean {
    contract {
        returns(false) implies (this@isNullOrBlank != null)
    }

    return this == null || this.isBlank()
}


二、Kotlin中的基本类型

        接下来我们来认识Kotlin中的基本类型,Java中有int,boolean等基本类型,也有对应的Integer,Boolean对基本类型的包装,区别在于基础类型一定是非空的。而在Kotlin中,是不进行区分的,Kotlin中不分区基本类型和包装类型,只有一种类型供我们使用,当需要设置为空的时候,和前面的一样,加上问号“?”声明为可空类型即可.

        (1)数字的转换

        在Kotlin中,不能像Java那样直接将Int类型的变量赋值给Long,需要使用显式的转换方法去赋值

        val i = 1
        //val l : Long = i //此处编译无法通过,需要显式的转换
        val l = i.toFloat() //这些类型之间都有转换方法,直接调用即可

        (2)Any、Unit和Nothing

        Any类型是Kotlin中所有类型的根类型,就像Java中的Object,不同的是,java中Object只能表示引用类型,不能表示int这样的基本类型,而在Kotlin中,Any可以表示Int这样的基本类型。同理,Any?就是所有可空类型的根类型。

        Unit类型就像Java中void一样,当不需要返回信息的时候,我们可以在方法的返回类型那里写为Unit,大多数情况下,我们使用的场景和Java中的void相同,当然,也有不同的地方,当我们重写一个泛型为返回类型的方法的时候,可以将返回类型声明为Unit,这样就不需要再书写return了,如

/**
 * 创建一个接口,并拥有一个需要返回泛型的方法
 */
interface Processoor<T>
{
    fun process():T 
}

class NoResultProcessor : Processoor<Unit>
{
    override fun process() {
        TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
        //因为指定了泛型为Unit,此时就不需要显式的书写return
    }
}

        Noting适用于那些永远不会执行完的方法,在某些方法中,我们一定会抛出异常,或者执行无限循环而永远不会结束,这种方法设置返回类型就没有意义了,此时,这种方法可以将返回值设置为Nothing

    open class Person(var age : Int = 0, var name : String = "", var addr : String? = null)
    var person : Person = Person(20) //Person 的addr是可空类型,此时为null
    val addr : String = person3.addr ?: fail("")//此时编译器可以判断出,如果为null会报错,所以addr可以声明为非空类型String
    fun fail(errorMessage : String) : Nothing
    {
        throw IllegalStateException(errorMessage)
    }


三、集合和数组

        接下来我们看Kotlin和Java中集合、数组相关的区别:前面我们知道,Kotlin中将数组也整合为了集合,集合声明的时候,存在集合可空和集合内元素可空的两种情况,声明方式如下:

    var list : ArrayList<String?>? = null

        Kotlin与Java在集合的另一个重要区别是,Kotlin中有可变集合和只读集合两种方式。看源码,在Collection类中,只有读取参数的方法,没有任何修改集合内容的方法提供,而修改集合相关的接口在MutableCollection中。

/**
 * A generic collection of elements. Methods in this interface support only read-only access to the collection;
 * read/write access is supported through the [MutableCollection] interface.
 * @param E the type of elements contained in the collection. The collection is covariant on its element type.
 */
public interface Collection<out E> : Iterable<E> {
    // Query Operations
    /**
     * Returns the size of the collection.
     */
    public val size: Int

    /**
     * Returns `true` if the collection is empty (contains no elements), `false` otherwise.
     */
    public fun isEmpty(): Boolean

    /**
     * Checks if the specified element is contained in this collection.
     */
    public operator fun contains(element: @UnsafeVariance E): Boolean

    override fun iterator(): Iterator<E>

    // Bulk Operations
    /**
     * Checks if all elements in the specified collection are contained in this collection.
     */
    public fun containsAll(elements: Collection<@UnsafeVariance E>): Boolean
}

/**
 * A generic collection of elements that supports adding and removing elements.
 *
 * @param E the type of elements contained in the collection. The mutable collection is invariant on its element type.
 */
public interface MutableCollection<E> : Collection<E>, MutableIterable<E> {
    // Query Operations
    override fun iterator(): MutableIterator<E>

    // Modification Operations
    /**
     * Adds the specified element to the collection.
     *
     * @return `true` if the element has been added, `false` if the collection does not support duplicates
     * and the element is already contained in the collection.
     */
    public fun add(element: E): Boolean

    /**
     * Removes a single instance of the specified element from this
     * collection, if it is present.
     *
     * @return `true` if the element has been successfully removed; `false` if it was not present in the collection.
     */
    public fun remove(element: E): Boolean

    // Bulk Modification Operations
    /**
     * Adds all of the elements in the specified collection to this collection.
     *
     * @return `true` if any of the specified elements was added to the collection, `false` if the collection was not modified.
     */
    public fun addAll(elements: Collection<E>): Boolean

    /**
     * Removes all of this collection's elements that are also contained in the specified collection.
     *
     * @return `true` if any of the specified elements was removed from the collection, `false` if the collection was not modified.
     */
    public fun removeAll(elements: Collection<E>): Boolean

    /**
     * Retains only the elements in this collection that are contained in the specified collection.
     *
     * @return `true` if any element was removed from the collection, `false` if the collection was not modified.
     */
    public fun retainAll(elements: Collection<E>): Boolean

    /**
     * Removes all elements from this collection.
     */
    public fun clear(): Unit
}
        这样做的好处在于,如果一个方法需要的入参是Collection类型,那么我们可以知道这个方法不会修改集合中的元素,而如果一个方法的参数是MutableCollection,我们就要考虑这个方法可能修改我们传入的集合,是否需要传入一个copy的集合过去,从而不影响我们当前保存集合的完整性。


        到此为止,我们已经学会了Kotlin的基本用法,已经可以将Java语言转换为Kotlin了,可以正常的用Kotlin书写代码了,后面我们将学习在Kotlin中如何构建我们的APi,让Kotlin更加好用!

        //  下一章 新手上路,Kotlin学习笔记(六)---运算符重载和其它约定


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值