博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Kotlin:娶妻当娶贤,嫁夫则嫁能
阅读量:6292 次
发布时间:2019-06-22

本文共 13537 字,大约阅读时间需要 45 分钟。

先来说个故事:

先来说个故事: 在万恶的旧社会,青年谷某当年迫于父母(市场)之命,取Oracle家长女java为妻。婚后虽不甜蜜也倒还相敬如宾。没过几年,谷某在生意场上风生水起,java娘家见此不禁眼红。打了好几场官司要讨回那些年谷某忘了给的彩礼。每每搞得谷某头大不已,借酒浇愁。 直至那晚回廊前红灯下,笙歌散后酒初醒,院也深来夜也深,月儿静来人也静。 后才得知,彼时佳人乃是JetBrains家的小女Kotlin。谷某见之倾心,不能自拔。而JetBrains看谷某丰神俊朗,又兼着谷氏所有商号掌柜之掌柜(大大掌柜?),真真是人中龙凤;倒也乐见其成。 再后来,坊间风声渐走。JetBrains便寻了谷某,要他给kotlin一个名份。谷某想着Java一日夫妻百日恩,虽说丈人家心狠也怨不得她。但若就此拖着kotlin岂不给天下人看了笑话去。牙一咬,心一横。在一年一次的谷氏大宴宣布:宴乃婚宴,妻乃平妻。 众人哗然,欢喜者有之;厌恶者有之,后悔当初没能及时结交上JetBrains者亦有之。 也是至此,谷家大宅院正式成为了J、K二凰争锋的大舞台......

作者:君莫笑
链接:https://www.zhihu.com/question/25289041/answer/174134423
来源:知乎

以上是转自知乎的一个段子,因为oracle的步步紧逼,谷歌爸爸终于在2017年5月18日宣布宣布Kotlin成为Android开发一级语言,自此Kotlin正式进入众多开发者的眼中。

那为什么是Kotlin?
下面是官网给的解释

那么Google中意Kotlin究竟为哪般呢?

兼容性

  1. Kotlin与JDK6完全兼容,确保Kotlin应用程序可以在较旧的Android设备上运行,无任何问题。
  2. Kotlin与Android构建系统兼容,并且在出来的Android Studio3.0预览版中已经完全不需要插件的形式进行Kotlin开发,可以实现Java代码一键转为Kotlin代码了。

性能

Kotlin应用程序运行速度与Java类似,非常类似的字节码结构。随着Kotlin对内联函数的支持,使用lambdas的代码通常比使用Java编写的代码运行得更快。

互操作性

Kotlin可与Java进行100%互操作,允许在Kotlin应用程序中使用所有现有的Android库。 包括注释处理,所以Data Binding和Butter Knife也是一样。

占用空间

Kotlin有一个非常紧凑的运行时库,可以通过使用ProGuard进一步减少。在真实的应用程序中,Kotlin运行时只添加了几百种方法,并且小于等于100K的.apk文件的大小。

编译性能

Kotlin支持高效的增量编译,因此,对于清理构建来说,增加的构建通常与Java一样快或更快。

Kotlin的基本语法,看这一篇就够啦~

函数定义

函数定义使用关键字fun,参数格式为:参数:类型

fun sum(a: Int, b: Int): Int {   // Int 参数,返回值 Int    return a + b}复制代码

表达式作为函数体时,返回类型自动判断

fun sum(a: Int, b: Int) = a + b复制代码

注意

// public 方法则必须明确写出返回类型public fun sum(a: Int, b: Int): Int = a + b   复制代码

无返回值的函数(类似Java中的void):

fun printSum(a: Int, b: Int): Unit {     print(a + b)}// 如果是返回 Unit类型,则可以省略(对于public方法也是这样):public fun printSum(a: Int, b: Int) {     print(a + b)}复制代码

常量定义和变量定义

  1. 可变变量定义:var关键字
var 
<标识符>
:
<类型>
=
<初始化值>
复制代码
  1. 不可变变量定义:val 关键字,只能赋值一次的变量(类似Java中final修饰的变量)
val 
<标识符>
:
<类型>
=
<初始化值>
复制代码

常量与变量都可以没有初始化值,但是在引用前必须初始化 编译器支持自动类型判断,即声明时可以不指定类型,由编译器判断。

示例:

val a: Int = 1val b = 1       // 系统自动推断变量类型为Intval c: Int      // 如果不在声明时初始化则必须提供变量类型c = 1           // 明确赋值var x = 5        // 系统自动推断变量类型为Intx += 1           // 变量可修改复制代码

注释

和java类似,支持单行注释和多行注释,不同的是,Kotlin中的块注释允许嵌套

// 这是一个单行注释/* 这是一个多行的   块注释。 */复制代码

字符串模板

表示一个变量名或者变量值varName 表示变量值 ${varName.fun()} 表示变量的方法返回值

var a = 1// 模板中的简单名称:val s1 = "a is $a" a = 2// 模板中的任意表达式:val s2 = "${s1.replace("is", "was")}, but now is $a"复制代码

NULL 检查机制

Kotlin的空安全设计对于声明可为空的参数,在使用时要进行空判断处理,有两种处理方式,字段后加!!像Java一样抛出空异常,另一种字段后加?可不做处理返回值为 null或配合?:做空判断处理

//类型后面加?表示可为空var age: String? = "23" //抛出空指针异常val ages = age!!.toInt()//不做处理返回 nullval ages1 = age?.toInt()//age为空返回-1val ages2 = age?.toInt() ?: -1复制代码

区间

区间表达式由具有操作符形式 .. 的 rangeTo 函数辅以 in 和 !in 形成。 区间是为任何可比较类型定义的,但对于整型原生类型,它有一个优化的实现。以下是使用区间的一些示例:

for (i in 1..4) print("$i ")    //输出1 2 3 4    println()    for (i in 4..1) print("$i ")    //什么也不输出4    println()    for (i in 4 downTo 1) print("$i ")    //倒序应该用downTo    println()    for (i in 1..10) {        // 等同于 1 <= i && i <= 10        //[1,10]        print("$i ")    }    println()    // 使用 until 函数排除结束元素    for (i in 1 until 10) {        // 等同于 1 <= i && i < 10        //[1,10)        print("$i ")    }    println()    for (i in 1..4 step 2) print("$i ")         //输出1 3    println()    for (i in 4 downTo 1 step 2) print("$i ")   //输出4 2    println()复制代码

Kotlin基本数据类型

| 类型 | 位宽度 | | -------- | -----:

| Double | 64
| Float | 32
| Long | 64
| Int | 32
| Short | 16 | Byte | 8

比较两个数字

在 Kotlin 中,三个等号 === 表示比较对象地址,两个 == 表示比较两个值大小。

fun main(args: Array
) { val a: Int = 10000 println(a === a) // true,值相等,对象地址相等 //经过了装箱,创建了两个不同的对象 val boxedA: Int? = a val anotherBoxedA: Int? = a //虽然经过了装箱,但是值是相等的,都是10000 println(boxedA === anotherBoxedA) // false,值相等,对象地址不一样 println(boxedA == anotherBoxedA) // true,值相等}复制代码

类型转换

每种数据类型都有下面的这些方法,可以转化为其它的类型:

toByte(): BytetoShort(): ShorttoInt(): InttoLong(): LongtoFloat(): FloattoDouble(): DoubletoChar(): Char复制代码

例如:

val b: Byte = 1 // OK, 字面值是静态检测的val i: Int = b.toInt() // OK复制代码

Kotlin条件控制

Kotlin中表达条件控制的有两种表达式

  1. if表达式
  2. when表达式

if表达式的用法

其实个人感觉对于if的用法,java和kotlin并没有什么区别,有点不太一样的就是可以把if表达式的结果赋值给一个变量,如下:

val max = if (a > b) {    print("Choose a")    a} else {    print("Choose b")    b}复制代码

所以也就可以有下面这样的写法了

val c = if (condition) a else b复制代码

when表达式的用法

when表达式就和java里面的switch类似,最简单的形式如下:

when (x) {    1 -> print("x == 1")    2 -> print("x == 2")    else -> { // 注意这个块        print("x 不是 1 ,也不是 2")    }}复制代码

在when语句中,else同switch语句中的default,如果其他分支都不满足条件将会进入else分支,当然,如果很多分支需要相同的处理方式,可以把多个分支条件放在一起,用逗号分隔,例如:

when (x) {    0, 1 -> print("x == 0 or x == 1")    else -> print("otherwise")}复制代码

我们也可以检测一个值在(in)或者不在(!in)一个区间或者集合中:

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")}复制代码

另一种可能性是检测一个值是(is)或者不是(!is)一个特定类型的值。注意: 由于智能转换,你可以访问该类型的方法和属性而无需 任何额外的检测。

fun hasPrefix(x: Any) = when(x) {    is String -> x.startsWith("prefix")    else -> false}复制代码

实例:

fun main(args: Array
) { val x = 0 if (x > 0) { println("x大于0") } else if (x == 0) { println("x等于0") } else { println("小于0") } val a = 1 val b = 2 val c = if (a >= b) a else b println("c的值为 $c") when (x) { 0, 1 -> println("x==0 or x==1") else -> println("otherwise") } when (x) { 1 -> println("x==1") 2 -> println("x==2") else -> { println("x 不是1,也不是2") } } when (x) { in 0..10 -> println("x在该区间范围内") else -> println("x不在该区间范围内") }}复制代码

Kotlin循环控制

和Java一样,kotlin循环也有三种形式,for循环,while循环和do....while循环。但是用法却有些不同。

for循环

基本用法如下:

for (item: Int in ints) {    // ……}复制代码

实例如下:

fun main(args: Array
) { val items = listOf("apple", "banana", "kiwi") for (item in items) { println(item) } for (index in items.indices) { println("item at $index is ${items[index]}") }}复制代码

执行结果如下:

applebananakiwiitem at 0 is appleitem at 1 is bananaitem at 2 is kiwi复制代码

注意!!

在kotlin中使用的for循环语句和java里面的for循环语句相类似,但是不可以使用 for(int i=0;i<n;i++)这样的语句

while循环和do...while循环

while循环是最基本的循环方式,基本结构为:

while( 布尔表达式 ) { //循环内容}复制代码

do...while 循环的基本结构为:

do {       //代码语句}while(布尔表达式);复制代码

理解起来和Java里面的while循环和do...while循环一致,参考实例如下:

fun main(args: Array
) { println("----while 使用-----") var x = 5 while (x > 0) { println( x--) } println("----do...while 使用-----") var y = 5 do { println(y--) } while(y>0)}复制代码

输出结果:

----while 使用-----54321----do...while 使用-----54321复制代码

循环返回和跳转

Kotlin 有三种结构化跳转的表达式:

  1. return
  2. break
  3. continue 理解起来和Java中的一样,基本用法也一致,但是在kotlin中break和continue有新的用法

Break 和 Continue 标签

在 Kotlin 中任何表达式都可以用标签(label)来标记。 标签的格式为标识符后跟 @ 符号,例如:abc@、fooBar@都是有效的标签。 要为一个表达式加标签,我们只要在其前加标签即可。

loop@ for (i in 1..100) {    for (j in 1..100) {        if (……) break@loop    }}复制代码

标签限制的 break 跳转到刚好位于该标签指定的循环后面的执行点。 continue 继续标签指定的循环的下一次迭代。

通过指定标签就可以明确的指定出在什么时候退出哪一个循环

Kotlin类和对象

Kotlin类中可以包含以下几个东西:

  1. 构造函数和初始化代码块
  2. 成员函数
  3. 属性
  4. 内部类
  5. 对象声明

Kotlin中使用关键字***class***声明类,后面紧跟类名,在类中可以定义成员函数,格式如下:

class Temp{    //类名为Temp    //大括号里面是类体构成    fun f(){        println("这是成员函数")    }}复制代码

类的属性

类的属性用关键字***var***声明为可变的,否则就用***val***声明为不可变

class Temp{    var name: String = ……    var url: String = ……    var city: String = ……}复制代码

也可以像使用普通函数那样使用构造函数创建类实例:

val temp= Temp() // Kotlin 中没有 new 关键字复制代码

想要使用一个属性,只需要用名称引用即可

temp.nametemp.url复制代码

这里需要注意的是,kotlin中并没有new关键字,实例化一个对象的时候不需要像java一样通过new关键字实例化。

getter和setter

getter和setter属性都是可选的,用法和c#中的get和set方法类似 如果属性类型可以从初始化语句或者类的成员函数中推断出来,那就可以省去类型

注意!!! val不允许设置setter函数,因为该函数是只读的。

var allByDefault: Int? // 错误: 需要一个初始化语句, 默认实现了 getter 和 setter 方法var initialized = 1    // 类型为 Int, 默认实现了 getter 和 setterval simple: Int?       // 类型为 Int ,默认实现 getter ,但必须在构造函数中初始化val inferredType = 1   // 类型为 Int 类型,默认实现 getter复制代码

实例

下面实例定义了一个Person类,包含两个可变变量 lastName 和 no,lastName 修改了 getter 方法,no 修改了 setter 方法。

class Person {    var lastName: String = "zhang"        get() = field.toUpperCase()   // 将变量赋值后转换为大写        set    var no: Int = 100        get() = field                // 后端变量        set(value) {            if (value < 10) {       // 如果传入的值小于 10 返回该值                field = value            } else {                field = -1         // 如果传入的值大于等于 10 返回 -1            }        }    var heiht: Float = 145.4f        private set}// 测试fun main(args: Array
) { var person: Person = Person() person.lastName = "wang" println("lastName:${person.lastName}") person.no = 9 println("no:${person.no}") person.no = 20 println("no:${person.no}")}复制代码

输出结果为:

lastName:WANGno:9no:-1复制代码

Kotlin 中类不能有字段。提供了 Backing Fields(后端变量) 机制,备用字段使用field关键字声明,field 关键词只能用于属性的访问器

主构造器和次构造器

Koltin 中的类可以有***一个*** 主构造器,以及***一个或多个***次构造器,主构造器是类头部的一部分,位于类名称之后:

class Person constructor(firstName: String) {}复制代码

如果主构造器没有任何注解,也没有任何可见度修饰符,那么可以省略constructor关键字

class Person(firstName: String) {}复制代码

主构造器

主构造器中不能包含任何代码,初始化代码可以当在初始化代码段中,用init关键字作为前缀

class Person constructor(firstName: String) {    init {        System.out.print("FirstName is $firstName")    }}复制代码

实例:

class Runoob  constructor(name: String) {  // 类名为 Runoob    // 大括号内是类体构成    var url: String = "http://www.runoob.com"    var country: String = "CN"    var siteName = name    init {        println("初始化网站名: ${name}")    }    fun printTest() {        println("我是类的函数")    }}fun main(args: Array
) { val runoob = Runoob("菜鸟教程") println(runoob.siteName) println(runoob.url) println(runoob.country) runoob.printTest()}复制代码

次构造函数

类也可以有二级构造函数,并且可以有多个,需要加前缀constructor

class Person {     constructor(parent: Person) {        parent.children.add(this)     }}复制代码

如果类有主构造函数,每个次构造函数都要,或直接或间接通过另一个次构造函数代理主构造函数。在同一个类中代理另一个构造函数使用 this 关键字:

class Person(val name: String) {    constructor (name: String, age:Int) : this(name) {        // 初始化...    }}复制代码

实例:

class Runoob  constructor(name: String) {  // 类名为 Runoob    // 大括号内是类体构成    var url: String = "http://www.runoob.com"    var country: String = "CN"    var siteName = name    init {        println("初始化网站名: ${name}")    }    // 次构造函数    constructor (name: String, alexa: Int) : this(name) {        println("Alexa 排名 $alexa")    }    fun printTest() {        println("我是类的函数")    }}fun main(args: Array
) { val runoob = Runoob("菜鸟教程", 10000) println(runoob.siteName) println(runoob.url) println(runoob.country) runoob.printTest()}复制代码

Kotlin继承

kotlin中所有的类都继承Any类,如果一个类要被继承,需要使用open关键字进行修饰

open class Base(p: Int)           // 定义基类class Derived(p: Int) : Base(p)复制代码

构造函数

子类有主构造函数,则基类必须在主构造函数中立即初始化

open class Person(var name : String, var age : Int){// 基类}class Student(name : String, age : Int, var no : String, var score : Int) : Person(name, age) {}// 测试fun main(args: Array
) { val s = Student("Runoob", 18, "S12346", 89) println("学生名: ${s.name}") println("年龄: ${s.age}") println("学生号: ${s.no}") println("成绩: ${s.score}")}复制代码

子类中没有主构造函数

如果子类没有主构造函数,则必须在每一个二级构造函数中用 super 关键字初始化基类,或者在代理另一个构造函数。初始化基类时,可以调用基类的不同构造方法。

/**用户基类**/open class Person(name:String){    /**次级构造函数**/    constructor(name:String,age:Int):this(name){        //初始化        println("-------基类次级构造函数---------")    }}/**子类继承 Person 类**/class Student:Person{    /**次级构造函数**/    constructor(name:String,age:Int,no:String,score:Int):super(name,age){        println("-------继承类次级构造函数---------")        println("学生名: ${name}")        println("年龄: ${age}")        println("学生号: ${no}")        println("成绩: ${score}")    }}fun main(args: Array
) { var s = Student("Runoob", 18, "S12345", 89)}复制代码

重写

如果允许子类重写,那么就要手动添加open修饰,重写的方法用override关键词修饰:

/**用户基类**/open class Person{    open fun study(){       // 允许子类重写        println("我毕业了")    }}/**子类继承 Person 类**/class Student : Person() {    override fun study(){    // 重写方法        println("我在读大学")    }}fun main(args: Array
) { val s = Student() s.study();}复制代码

如果有多个相同的方法(继承或者实现自其他类,如A、B类),则必须要重写该方法,使用super范型去选择性地调用父类的实现。

open class A {    open fun f () { print("A") }    fun a() { print("a") }}interface B {    fun f() { print("B") } //接口的成员变量默认是 open 的    fun b() { print("b") }}class C() : A() , B{    override fun f() {        super.f()//调用 A.f()        super.f()//调用 B.f()    }}fun main(args: Array
) { val c = C() c.f();}复制代码

Kotlin接口

在kotlin中接口和java8中的用法类似,都是用interface关键字定义接口,允许有默认方法的实现。

接口中的方法

实例:

interface MyInterface {    fun bar()    fun foo() {        // 可选的方法体        println("foo")    }}class Child : MyInterface {    override fun bar() {        // 方法体        println("bar")    }}fun main(args: Array
) { val c = Child() c.foo(); c.bar();}复制代码

接口中的属性

接口中的属性只能是抽象的,不允许初始化值,接口不会爆粗 属性值,实现接口的时候,必须重写属性。 实例:

interface MyInterface {    var name:String //name 属性, 抽象的    fun bar()    fun foo() {        // 可选的方法体        println("foo")    }}class Child : MyInterface {    override var name: String = "runoob" //重载属性    override fun bar() {        // 方法体        println("bar")    }}fun main(args: Array
) { val c = Child() c.foo(); c.bar(); println(c.name) }复制代码

函数重写

接口中的方法的重写和继承类中的方法重写类似,实例如下:

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.foo()        super.foo()    }     override fun bar() {        super.bar()    }} fun main(args: Array
) { val d = D() d.foo(); d.bar();}复制代码

开发IDE : /

参考:

转载地址:http://tlkta.baihongyu.com/

你可能感兴趣的文章
第十三章 RememberMe——《跟我学Shiro》
查看>>
mysql 时间函数 时间戳转为日期
查看>>
索引失效 ORA-01502
查看>>
Oracle取月份,不带前面的0
查看>>
Linux Network Device Name issue
查看>>
IP地址的划分实例解答
查看>>
如何查看Linux命令源码
查看>>
运维基础命令
查看>>
入门到进阶React
查看>>
SVN 命令笔记
查看>>
检验手机号码
查看>>
重叠(Overlapped)IO模型
查看>>
Git使用教程
查看>>
使用shell脚本自动监控后台进程,并能自动重启
查看>>
Flex&Bison手册
查看>>
solrCloud+tomcat+zookeeper集群配置
查看>>
/etc/fstab,/etc/mtab,和 /proc/mounts
查看>>
Apache kafka 简介
查看>>
socket通信Demo
查看>>
技术人员的焦虑
查看>>