美文网首页
Hello Kotlin

Hello Kotlin

作者: Discredited | 来源:发表于2019-06-20 21:53 被阅读0次

Java转Kotlin,对语法、声明和一些符号的使用不是很清楚,特此记录

变量定义方式

val 只读变量,只能赋值一次
var 读写变量,可多次赋值

val a: Int = 1  // 立即赋值
val b = 2   // 自动推断出 `Int` 类型
val c: Int  // 如果没有初始值类型不能省略
c = 3       // 明确赋值

理解自动类型推断

函数的定义

//带有两个 Int 参数、返回 Int 的函数:
fun sum(a: Int, b: Int): Int {
    return a + b
}

//将表达式作为函数体、返回值类型自动推断的函数:
fun sum(a: Int, b: Int) = a + b

//将表达式作为函数体、返回值类型自动推断的函数:
fun printSum(a: Int, b: Int): Unit {
    println("sum of $a and $b is ${a + b}")
}

//Unit 返回类型可以省略:
fun printSum(a: Int, b: Int) {
    println("sum of $a and $b is ${a + b}")
}

模板字符串

在字符串中引用变量,或者在字符串中使用任意表达式

var a = 1
val s1 = "a is $a1"

a = 2
val s2 = "${s1.replace("is", "was")}, but now is $a"

s2的输出结:a was 1, but now is 2

表达式

与Java类似,if(){}if(){}else{}

fun maxOf(a: Int, b: Int): Int {
    if (a > b) {
        return a
    } else {
        return b
    }
}

fun maxOf(a: Int, b: Int) = if (a > b) a else b

两种写法都一样

空值检测和和使用

当某个变量的值可以为 null 的时候,必须在声明处的类型后添加 ? 来标识该引用可为空

fun parseInt(str: String): Int? {
    //表示该方法可以返回一个整型或者null
}

使用类型检测及自动类型转换

is 运算符检测一个表达式是否某类型的一个实例。 如果一个不可变的局部变量或属性已经判断出为某类型,那么检测后的分支中可以直接当作该类型使用,无需显式转换:

fun getStringLength(obj: Any): Int? {
    if (obj is String) {
        // `obj` 在该条件分支内自动转换成 `String`
        return obj.length
    }

    // 在离开类型检测分支后,`obj` 仍然是 `Any` 类型
    return null
}

fun getStringLength(obj: Any): Int? {
    // `obj` 在 `&&` 右边自动转换成 `String` 类型
    if (obj is String && obj.length > 0) {
      return obj.length
    }

    return null
}

emmmm.....这里的is和Java的instanceof是一个意思,其中is作用范围内自动转换数据类型比较Java方便了不少

if条件表达式

// 传统用法
var max = a 
if (a < b) max = b

// With else 
var max: Int
if (a > b) {
    max = a
} else {
    max = b
}
 
// 作为表达式
val max = if (a > b) a else b

//if的分支可以是代码块,最后的表达式作为该块的值
val max = if (a > b) {
    print("Choose a")
    a
} else {
    print("Choose b")
    b
}

与Java的if不同在于,Kotlin的if可以作为语句,也可一作为表达式,当它作为表达式时,每一个分支中最后一个表达式的值为分支的值

When表达式

Kotlin使用when取代了switch

when (x) {
    1 -> print("x == 1")
    2 -> print("x == 2")
    else -> { // 注意这个块
        print("x is neither 1 nor 2")
    }
}

//多分支合并,和switch真的很像
when (x) {
    0, 1 -> print("x == 0 or x == 1")
    else -> print("otherwise")
}

//任意表达是作为分支
when (x) {
    parseInt(s) -> print("s encodes x")
    else -> print("s does not encode x")
}

//任意区间判断作为分支
when (x) {
    in 1..10 -> print("x is in the range")
    in validNumbers -> print("x is valid")
    !in 10..20 -> print("x is outside the range")
    else -> print("none of the above")
}

//Since Kotlin 1.3, it is possible to capture when subject in a variable using following syntax:
//强大到令人发指??
fun Request.getBody() =
        when (val response = executeRequest()) {
            is Success -> response.body
            is HttpError -> throw HttpException(response.status)
        }

和if一样,when也可以作为表示式使用,但是需要注意:如果 when 作为一个表达式使用,则必须有 else 分支, 除非编译器能够检测出所有的可能情况都已经覆盖了

伴生对象

类内部的对象声明可以用 companion 关键字标记

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

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

val instance = MyClass.create()

其自身所用的类的名称(不是另一个名称的限定符)可用作对该类的伴生对象 (无论是否命名)的引用

class MyClass1 {
    companion object Named { }
}

val x = MyClass1

class MyClass2 {
    companion object { }
}

val y = MyClass2

emmm...看起来很像Java的static,但是它不是static,请注意,即使伴生对象的成员看起来像其他语言的静态成员,在运行时他们仍然是真实对象的实例成员,而且,例如还可以实现接口

interface Factory<T> {
    fun create(): T
}

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

val f: Factory<MyClass> = MyClass

对象表达式和对象声明之间有一个重要的语义差别:
对象表达式是在使用他们的地方**立即**执行(及初始化)的
对象声明是在第一次被访问到时**延迟**初始化的
伴生对象的初始化是在相应的类被加载(解析)时,与 Java 静态初始化器的语义相匹配

创建基本类和实例

不需要关键字new,直接类名称就能创建一个对象

val rectangle = Rectangle(5.0, 2.0) // 不需要“new”关键字
val triangle = Triangle(3.0, 4.0, 5.0)

主构造函数和次构造函数以及初始化

在 Kotlin 中的一个类可以有一个主构造函数以及一个或多个次构造函数。主构造函数是类头的一部分:它跟在类名(与可选的类型参数)后

class Person constructor(firstName: String) { ... }

//如果主构造函数没有任何注解或者可见性修饰符,可以省略这个 constructor 关键字
class Person(firstName: String) { ... }

//事实上,声明属性以及从主构造函数初始化属性,Kotlin 有简洁的语法:
class Person(val firstName: String, val lastName: String, var age: Int) { …… }

主构造函数不能包含任何的代码
初始化代码应该放在init{}

在实例初始化期间,初始化块按照它们出现在类体中的顺序执行,与属性初始化器交织在一起

class InitOrderDemo(name: String) {
    val firstProperty = "First property: $name".also(::println)
    
    init {
        println("First initializer block that prints ${name}")
    }
    
    val secondProperty = "Second property: ${name.length}".also(::println)
    
    init {
        println("Second initializer block that prints ${name.length}")
    }
}

fun main() {
    InitOrderDemo("hello")
}

First property: hello
First initializer block that prints hello
Second property: 5
Second initializer block that prints 5

如果一个非抽象类没有声明任何(主或次)构造函数,它会有一个生成的不带参数的主构造函数。构造函数的可见性是 public
这一点和Java挺像的

类也可以声明前缀有 constructor的次构造函数

class Person {
    constructor(parent: Person) {
        parent.children.add(this)
    }
}

如果类有一个主构造函数,每个次构造函数需要委托给主构造函数, 可以直接委托或者通过别的次构造函数间接委托。委托到同一个类的另一个构造函数用 this 关键字即可

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

属性、访问器、幕后字段、幕后属性

这里我看api文档是真的没有看懂。。。。。。感谢依然范特希西大佬
Kotlin 什么是幕后字段?

接口

使用关键字 interface 来定义接口
Kotlin 的接口与 Java 8 类似,既包含抽象方法的声明,也包含实现。
需要注意实现多个接口冲突的覆盖

//接口的定义
interface MyInterface {
    fun bar()
    fun foo() {
      // 可选的方法体
    }
}


/**在接口中声明的属性要么是抽象的,要么提*供访问器的实现。
在接口中声明的属性不能有幕后字段(backingfield),
因此接口中声明的访问器不能引用它们*/
interface MyInterface {
    val prop: Int // 抽象的

    val propertyWithImplementation: String
        get() = "foo"

    fun foo() {
        print(prop)
    }
}


//接口冲突的覆盖和重写
class Child : MyInterface {
    override val prop: Int = 29
}

interface A {
    fun foo() { print("A") }
    fun bar()
}

interface B {
    fun foo() { print("B") }
    fun bar() { print("bar") }
}

class C : A {
    override fun bar() { print("bar") }
}

class D : A, B {
    override fun foo() {
        super<A>.foo()
        super<B>.foo()
    }

    override fun bar() {
        super<B>.bar()
    }
}

接口里面不仅是声明方法,还可以定义方法体。。。但是和抽象类还是有很大的区别,与抽象类不同的是,接口无法保存状态。它可以有属性但必须声明为抽象或提供访问器实现。

访问修饰符

  • 如果你不指定任何可见性修饰符,默认为 public,这意味着你的声明将随处可见;
  • 如果你声明为 private,它只会在声明它的文件内可见;
  • 如果你声明为 internal,它会在相同模块内随处可见;
  • protected 不适用于顶层声明。

对模块的理解:可见性修饰符 internal 意味着该成员只在相同模块内可见。更具体地说, 一个模块是编译在一起的一套 Kotlin 文件:

  • 一个 IntelliJ IDEA 模块;
  • 一个 Maven 项目;
  • 一个 Gradle 源集(例外是 test 源集可以访问 main 的 internal 声明);
  • 一次 <kotlinc> Ant 任务执行所编译的一套文件。

扩展函数和扩展属性

声明一个扩展函数,我们需要用一个 接收者类型 也就是被扩展的类型来作为他的前缀。 下面代码为 MutableList<Int> 添加一个swap 函数:

fun MutableList<Int>.swap(index1: Int, index2: Int) {
    val tmp = this[index1] // “this”对应该列表
    this[index1] = this[index2]
    this[index2] = tmp
}

与函数类似,Kotlin 支持扩展属性:

val <T> List<T>.lastIndex: Int
    get() = size - 1

注意:由于扩展没有实际的将成员插入类中,因此对扩展属性来说幕后字段是无效的。这就是为什么扩展属性不能有初始化器。他们的行为只能由显式提供的 getters/setters 定义。

相关文章

  • Kotlin 学习笔记

    目录 Hello Kotlin 搭建 Kotlin 学习环境(SpringBoot 版)解读 hello-kotl...

  • Hello,Kotlin!

    . 安装Kotlin插件 . 附上Hello,Kotlin 地址

  • Hello Kotlin

    Kotlin设计哲学 简洁,实用,安全。 定义方法 kotlin语言很多概念和Java一样,所以有Java经验的人...

  • Hello Kotlin

    在此仅整理所学资料原文地址: 《Kotlin for android developers》中文版翻译 介绍 什么...

  • Hello Kotlin

    HelloKotlin Foreword 首先,献上官方网址:Kotlin,官方介绍它是用于现代多平台应用的静态类...

  • Hello,Kotlin

    第一次接触Kotlin是在好几个月前的事了,是在Bugly推送的一篇文章中看到的,PS:腾讯的同学还是很有先知先觉...

  • hello kotlin

    最近用java写串口数据通信的程序,没有unsigned类型真的累 :) 刚刚看了一眼kotlin,soooooo...

  • Hello Kotlin

    Java转Kotlin,对语法、声明和一些符号的使用不是很清楚,特此记录 变量定义方式 val 只读变量,只能赋值...

  • 初探Kotlin(二)

    Hello World 先来一个Kotlin 中的Hello worldfun main(args: Array ...

  • Kotlin初探--------Hello Kotlin

    Kotlin现在貌似很火的样子,身为Android开发人员也不得不来尝试一下。 Android Studio配置使...

网友评论

      本文标题:Hello Kotlin

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