什么是Kotlin歉秫?
Kotlin是由JetBrains設(shè)計(jì)并開源的JVM編程語(yǔ)言蛾洛。Kotlin是使用Java開發(fā)者的思維創(chuàng)建的,Intellij作為它主要的開發(fā)IDE雁芙,因此對(duì)于Android開發(fā)者來(lái)說(shuō)它非常易于學(xué)習(xí)并能與AS和Gradle完美結(jié)合轧膘。
它的主要特點(diǎn)有:
1、簡(jiǎn)潔(函數(shù)式編程減少很多代碼)
2兔甘、安全(編譯時(shí)就處理了各種空指針的情況)
3谎碍、輕量級(jí)(Kotlin核心庫(kù)僅有不到7000個(gè)方法,大致和support-v4一樣)
4洞焙、高交互性(與Java混合編程)
5蟆淀、提供了更多特性
使用配置
1、Android Studio 安裝插件 Kotlin(原本還有 Kotlin Extensions For Android澡匪,已合入Kotlin)
2熔任、build.gradle 配置
buildscript {
ext.kotlin_version = '1.0.5-2'
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:${kotlin_version}"
}
}
apply plugin: 'kotlin-android‘
apply plugin: 'kotlin-android-extensions‘
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:${kotlin_version}"
}
基本語(yǔ)法
這里只列出一些與Java不同的地方,完整的語(yǔ)法參考文檔見文章最后鏈接
1仙蛉、基本類型
數(shù)值:Double笋敞,F(xiàn)loat,Long荠瘪,Int夯巷,Short赛惩,Byte
字符:Char
布爾:true,false
// 短類型不是長(zhǎng)類型的子類型趁餐,需要顯示轉(zhuǎn)換喷兼,數(shù)值和字符都有toXXX()方法
var a: Int = 100
var b: Long = a.toLong()
數(shù)組:Array
// 可以通過(guò) asc[0] 或 asc.get(0) 訪問(wèn)元素
// 可以通過(guò) asc.forEach{} 或 for(str in asc) {} 遍歷元素
var emptyArray = emptyArray<String>() // []
var nullArray = kotlin.arrayOfNulls<String>(3) // [null, null, null]
var numArray = arrayOf(1, 2, 3) // [1, 2, 3]
var asc = Array(5, { i -> (i * i).toString() }) // ["0", "1", "4", "9", "16"]
字符串:String
var str = "hello world"
訪問(wèn)和遍歷元素同Array
字符串模板:
var name = "Bob"
println("My name is $name") // 打印 My name is Bob
var a = 10
var b = 20
println("The sum is ${a+b}") // 打印 The sum is 30
2、變量與常量
var x: Int = 5 // 定義變量
var y = 5 // 能推導(dǎo)出類型后雷,可省略類型聲明
y++
val x: Int = 5 // 定義常量
val y = 5 // 能推導(dǎo)出類型季惯,可省略類型聲明
val z: Int // 當(dāng)沒有初始化值時(shí)必須聲明類型
z=1 // 只能賦值一次
const val INT_ONE: Int = 1 // 編譯時(shí)可確定值的常量可以用const修飾,但只能放在文件最外層
3臀突、流程控制
if表達(dá)式:
var max = if (a > b) a else b
var max = if (a > b) {
println("choose $a")
a
} else {
println("choose $b")
b
}
for表達(dá)式和Range:
for (i in 0..4) println(i) // 0,1,2,3,4
for (i in 4 downTo 0) println(i) // 4,3,2,1,0
for (i in 0..4 step 2) println(i) // 0,2,4
for (i in 4 downTo 0 step 2) println(i) // 4,2,0
for (i in 0 until 4) println(i) // 0,1,2,3
When表達(dá)式:
when(x) {
0 -> print("x == 0")
1,2 -> print("x == 1 or x == 2")
in 1..10 -> print("x is in the range")
is Int -> print(x + 1)
is String -> print(x.size() + 1) // 智能轉(zhuǎn)換
else -> print("otherwise")
}
4勉抓、定義函數(shù)
fun + 函數(shù)名 + 參數(shù) + 返回值 + 函數(shù)體
fun sum(a: Int , b: Int): Int { return a + b }
fun sum(a: Int, b: Int) = a + b // 與上句等價(jià)
fun printSum(a: Int, b: Int): Unit { print( a + b) } // 沒有返回值時(shí)為Unit
fun printSum(a: Int, b: Int) { print( a + b) } // Unit可省略
5、默認(rèn)參數(shù)
Java:
void introduce(String name, int age) {
println("Hi, My name is " + name + ", I am " + age);
}
void introduce(String name) {
introduce(name, 18);
}
Kotlin:
fun introduce(name: String, age: Int = 18) {
println("Hi, My name is $name, I am $age")
}
調(diào)用:
introduce("Bob")
introduce("Bob", 20)
6候学、類與構(gòu)造函數(shù)
class + 類名 + 類頭 + 類主體
// 最簡(jiǎn)單的類定義
class Person
// 有一個(gè)主構(gòu)造函數(shù)的類藕筋,其中constructor關(guān)鍵字省略掉了
class Person(var id: Long, var name: String, var age: Int)
// constructor有private關(guān)鍵字修飾,不能省略
// 主構(gòu)造函數(shù)的初始化只能在類主體的init塊中
// 二級(jí)構(gòu)造函數(shù)在類主體中定義梳码,需要用this調(diào)用主構(gòu)造函數(shù)
class Person private constructor(var id: Long, var name: String, var age: Int) {
init {
print("Person initialized with id ${id} name ${name} age ${age}")
}
constructor(person: Person) : this(person.id, person.name, person.age) {
}
}
所有的類都有共同的父類 Any
沒有new關(guān)鍵字隐圾,直接像使用普通函數(shù)那樣使用構(gòu)造函數(shù)創(chuàng)建類實(shí)例:
var person = Person(1, "Bob", 20)
7、數(shù)據(jù)類
data class User(var id: Long, var name: String, var age: Int)
自動(dòng)實(shí)現(xiàn)了get掰茶、set方法以及toString暇藏、equals、hashCode濒蒋、copy等方法盐碱,支持映射對(duì)象到變量。
data class Forecast(var date: Date, var temp: Float, var details: String)
var f1 = Forecast(Date(), 27.5f, "Shiny day")
var f2 = f1.copy(temp = 30f) // 變量名不可隨意
var (date, temp, details) = f1 // 變量名可以隨意沪伙,按順序映射
8甸各、繼承
Kotlin中所有的類和屬性以及方法都默認(rèn)是final的,如果需要被繼承則要加上open關(guān)鍵字焰坪,override標(biāo)記的方法默認(rèn)是open的趣倾,如果不想再被繼承可以加上final
open class Base {
open fun f1(){}
fun f2() {}
}
class Derived : Base() {
override fun f1() {}
}
9、接口
Kotlin中的接口可以有屬性和方法的默認(rèn)實(shí)現(xiàn)某饰,與抽象類的區(qū)別是接口的屬性是無(wú)狀態(tài)的儒恋,需要子類去重寫
Java:
public interface Flying {
void fly();
}
public class Bird implements Flying {
Wings wings = new BirdWings();
@Override
public void fly() {
wings.move();
}
}
public class Bat implements Flying {
Wings wings = new BatWings();
@Override
public void fly() {
wings.move();
}
}
Kotlin:
interface Flying {
var wings: Wings
fun fly() = wings.move()
}
class Bird : Flying {
override var wings: Wings = BirdWings()
}
class Bat : Flying {
override var wings: Wings = BatWings()
}
Kotlin中實(shí)現(xiàn)接口和繼承類一樣,都是通過(guò)冒號(hào) : 繼承黔漂,多個(gè)接口及類之間以逗號(hào) , 隔開诫尽,如果方法有多個(gè)實(shí)現(xiàn)則必須在子類中重寫方法,可以通過(guò)super<Base>指定調(diào)用哪個(gè)父類中的方法
open class A {
open fun f () {}
}
interface B {
fun f() {}
}
class C : A() , B{
override fun f() {
super<A>.f() // 調(diào)用 A.f()
super<B>.f() // 調(diào)用 B.f()
}
}
10炬守、空安全
var user: User = null // 這里不能通過(guò)編譯. user不能是null
var user: User? = null // user可以是 null
user.name // 無(wú)法編譯, user可能是null牧嫉,需要進(jìn)行判斷
user?.name // 只有在user != null時(shí)才會(huì)執(zhí)行
if (user != null) {
user.name // 智能轉(zhuǎn)換. 如果我們?cè)谥斑M(jìn)行了空檢查,則不需要使用安全調(diào)用操作符調(diào)用
}
user!!.name // 只有在確保user不是null的情況下才能這么調(diào)用,否則會(huì)拋出異常
var name = user?.name ?: "empty" // 使用Elvis操作符來(lái)給定一個(gè)在是null的情況下的替代值
11酣藻、函數(shù)擴(kuò)展
fun String.toast(context: Context) {
Toast.makeText(context, this, Toast.LENGTH_SHORT).show()
}
"abc".toast(context)
var sum = fun Int.(other: Int): Int = this + other
1.sum(2)
12曹洽、Lambda表達(dá)式
(params) -> expression
(params) -> statement
(params) -> { statements }
如果參數(shù)沒用到可以省略為 () -> { statements } 甚至 { statements }
view.setOnClickListener{Log.d(TAG, "click view")}
listOf<Int>(1, 2, 3, 4, 5).filter { it > 2 }.map { it * it } // [9, 16, 25]
插件
kotlin-android-extensions插件主要提供了對(duì)Android的支持
例如:不再需要findViewById,可直接通過(guò)id引用xml中的View
textView.text = "Hello World!";
textView.setOnClickListener { toast(textView.text.toString()) }
anko插件引入了DSL(Domain Specific Language)的方式開發(fā)Android界面布局,主要目的是用代碼代替xml實(shí)現(xiàn)界面布局
使用前:
<RelativeLayout>
<TextView
android:id="@+id/sample_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:text="Sample text view"
android:textSize="25sp" />
<Button
android:id="@+id/sample_button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/sample_text_view"
android:text="Sample button" />
</RelativeLayout>
使用后:
relativeLayout {
val textView = textView("Sample text view") {
textSize = 25f
}.lparams {
width = matchParent
alignParentTop()
}
button("Sample button").lparams {
width = matchParent
below(textView)
}
}
參考文檔
1辽剧、Kotlin API 中文文檔
https://github.com/huanglizhuo/kotlin-in-chinese
2送淆、Kotlin Android 開發(fā)中文文檔
https://github.com/wangjiegulu/kotlin-for-Android-developers-zh
3、Kotlin:Java 6 廢土中的一線希望
https://toutiao.io/posts/c55jha/preview
4怕轿、Kotlin 在線運(yùn)行
http://try.kotlinlang.org/
5偷崩、Android Studio中 code->Convert Java File to Kotlin File 自動(dòng)將Java文件轉(zhuǎn)換成Kotlin文件
另外由于Kotlin和Java之間的高交互性,可以一邊學(xué)習(xí)Kotlin的語(yǔ)法一邊一點(diǎn)點(diǎn)的替換現(xiàn)有代碼