美文网首页
Learn Kotlin

Learn Kotlin

作者: Big不吃鱼 | 来源:发表于2017-11-17 16:53 被阅读327次

    Kotlin优势

    • 空安全 :在编译时期处理各种null情况,避免执行时异常。
    • 函数式支持:它使用了很多函数式编程概念。
    • 扩展函数:可以给任何类添加扩展函数。
    • 高度互操作性:Kotlin和Java两个语言之间可以互操作,两种语言互相调用,混合编程。

    构造函数

    在 Kotlin 中的一个类可以有一个主构造函数和一个或多个次级构造函数。主构造函数是类头的一部分:它跟在类名后。

    //firstName可以在initializer blocks中使用
    class Person constructor(firstName: String) {
    }
    

    如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor关键字。

    class Person(firstName: String) {
    }
    

    主构造函数不能包含任何的代码。
    初始化的代码可以放到以 init 关键字作为前缀的初始化块(initializer blocks)中:

    class Person(name: String) {
        init {
            CLog.d("Person initialized with name ${name}")
        }
    }
    

    注意,主构造的参数可以在初始化块中使用。它们也可以在类体内中声明属性时使用:

    class Person(name: String) {
        val customerKey = name.toUpperCase()
    }
    

    事实上,声明属性以及从主构造函数初始化属性,Kotlin 有简洁的语法,与普通属性一样,主构造函数中声明的属性可以是可变的(var)或只读的(val):

    class Person(val firstName: String, val lastName: String, var age: Int) {
        // ……
    }
    

    如果构造函数有注解或可见性修饰符,这个 constructor 关键字是必需的,并且这些修饰符在它前面:

    class Person private constructor(name: String) {
        //......
    }
    

    次级构造函数

    类也可以声明前缀有 constructor的次构造函数。
    如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可。
    如果你没有委托主构造函数,系统会提示:Primary constructor call expected

    class Person(val name: String) {
        constructor(name: String, parent: Person) : this(name) {
            parent.children.add(this)
        }
    }
    

    如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造函数。构造函数的可见性是 public。如果你不希望你的类有一个公有构造函数,你需要声明一个带有非默认可见的空的主构造函数:

    class DontCreateMe private constructor () {
    }
    

    继承

    在 Kotlin 中所有类都有一个共同的超类 Any,它是没有继承父类的类的默认超类:

    class Example // 从 Any 隐式继承
    

    默认每个类在创建的时候都是final的,如果没有添加open关键字,你在继承的时候系统会提示This type is final, so it cannot be inherited from

    要声明一个显式的父类,我们把类型放到类头的冒号之后:

    open class Base(p: Int)
    class Derived(p: Int) : Base(p)
    

    如果该父类有一个主构造函数,则子类可以(并且必须) 用父类型的)主构造函数参数就地初始化。如果没有执行这一步,系统会提示This type has a constructor , and thus must be initailized here

    如果类没有主构造函数,那么每个次构造函数必须使用 super 关键字初始化其父类型,或委托给另一个构造函数做到这一点。 注意,在这种情况下,不同的次构造函数可以调用父类型的不同的构造函数:

    class MyView : View {
        constructor(context: Context) : super(context)
        constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
    }
    

    如果你不执行这一步,系统会提示你Explicit "this" or ''super" call is required. There is no constructor in superclass that can be called without arguments
    类上的open 标注与 Java 中 final 相反,它允许其他类从这个类继承。
    默认情况下,在 Kotlin 中所有的类都是 final。
    要么为继承而设计,并提供文档说明,要么就禁止继承。

    伴生对象

    在 Kotlin 中类没有static的方法和变量,所以需要使用Companion Object来声明类似static的方法和变量。
    其实这些变量并不是真正的static变量,而是一个伴生对象,这个伴生对象位于类中定义的一个叫做Companion的内部类中。
    类内部的对象声明可以用 companion 关键字标记:

    class MyClass {
        companion object Factory {
            fun create(): MyClass = MyClass()
        }
    }
    

    该伴生对象的成员可通过只使用类名作为限定符来调用:

    val instance = MyClass.create()
    

    在Java中如何调用Companion Object的属性和方法呢?

    MyClass.INSTANCE.create()
    

    当然,在 JVM 平台,如果使用 @JvmStatic @JvmField注解,你可以将伴生对象的成员生成为真正的
    静态方法和字段。

    我们来看一下Companion Object的具体应用场景:


    CapaCameraActivity.png

    字节码:


    字节码.png

    Decompile To Java:


    Decompile To Java.png

    Getter And Setter

    首先来看在Kotlin中如何声明一个属性,属性可以用关键字var 声明为可变的,否则使用只读关键字val

    class Address {
        var name: String = ……
        var street: String = ……
        var city: String = ……
        var state: String? = ……
        var zipCode: String = ……
    }
    

    其实,声明一个属性的完整语法是:

    var <propertyName>[: <PropertyType>] [= <property_initializer>]
        [<getter>]
        [<setter>]
    

    其中,initializer、setter、getter都是可选的。属性的类型如果可以从initializer或getter中推断出来,也可以省略。
    其中,一个只读属性(val)和一个可变属性(var)的区别是:只读属性不允许setter。

    一个自定义gettter的例子:

    val isEmpty: Boolean
        get() = this.size == 0
    

    一个自定义setter的例子:

    var stringRepresentation: String
        get() = this.toString()
        set(value) {
            setDataFromString(value) // 解析字符串并赋值给其他属性
        }
    

    如果你需要改变一个访问器的可见性或者对其注解,但是不需要改变默认的实现, 你可以定义访问器而不定义其实现:

    var setterVisibility: String = "abc"
        private set // 此 setter 是私有的并且有默认实现
    
    var setterWithAnnotation: Any? = null
        @Inject set // 用 Inject 注解此 setter
    

    具体使用场景:需要自定义getter和setter的方法举例:

    扩展函数

    扩展函数数是指在一个类上增加一种新的行为,甚至我们没有这个类代码的访问权限。
    Koltin可以对一个类的属性和方法进行扩展,它是一种静态行为,对扩展的类代码不会造成任何影响。
    扩展函数的定义形式:

    fun receiverType.functionName(params){
        body
    }
    
    • receiverType:表示函数的接收者,也就是函数扩展的对象
    • . :扩展函数的修饰符
    • functionName:扩展函数的名称
    • params:扩展函数的参数,可以为NULL

    一个简单的扩展函数的举例:

    //声明一个User类
    class User(var name:String)
    
    //定义一个简单的打印User名字的扩展函数
    fun User.Print(){
        print("用户名 $name")
    }
    
    fun main(arg:Array<String>){
        var user = User("Runoob")
        user.Print()
    }
    

    项目中已有的最简便的扩展函数的应用(ViewExtensions):

    package com.xingin.common
    
    import android.text.SpannableString
    import android.view.View
    import android.widget.TextView
    
    /**
     * Created by chris on 03/08/2017.
     */
    fun View.hide() {
        this.visibility = View.GONE
    }
    fun View.show() {
        this.visibility = View.VISIBLE
    }
    fun View.showIf(shouldShow: Boolean) {
        this.visibility = if (shouldShow) View.VISIBLE else View.GONE
    }
    fun View.hideIf(shouldHide: Boolean) {
        showIf(!shouldHide)
    }
    
    fun TextView.setTextOrHide(text: CharSequence) {
        this.text = text
        showIf(text.isNotEmpty())
    }
    
    
    import java.io.File
    
    /**
     * Created by Kathy on 2017/9/25.
     */
    fun File.mkdirIfNotExists() {
        if (!exists()) mkdirs()
    }
    
    fun File.deleteIfIsFile() {
        if (isFile && exists()) delete()
    }
    
    public final class FileExtensionsKt {
       public static final void mkdirIfNotExists(@NotNull File $receiver) {
          Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
          if(!$receiver.exists()) {
             $receiver.mkdirs();
          }
    
       }
    
       public static final void deleteIfIsFile(@NotNull File $receiver) {
          Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
          if($receiver.isFile() && $receiver.exists()) {
             $receiver.delete();
          }
    
       }
    

    Kotlin扩展函数允许我们在不改变已有类的情况下,为类添加新的函数。
    最常用的扩展函数的实例:

    fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
        Toast.makeText(this, message, duration).show()
    }
    

    然后在我们的Activity中将它作为普通方法来直接使用:

    override fun onCreate(savedInstanceState: Bundle?) { 
        toast("This is onCreate!!")
        toast("Hello world!", Toast.LENGTH_LONG)
        toast(message = "Hello world!", duration = Toast.LENGTH_LONG)
    }
    

    End

    相关文章

      网友评论

          本文标题:Learn Kotlin

          本文链接:https://www.haomeiwen.com/subject/oujupxtx.html