fun sum(a: Int, b: Int): Int {
return a + b
}
// 對於只有一行的函數,kotlin可以這麼簡寫,爽不?
fun sum(a:Int, b:Int): Int = a + b
可以看到函數的聲明是通過fun關鍵字的,函數的參數類型和參數名的位置跟Java是相反的,中間使用 : 分隔,函數的返回類型是放在最後的,當然也是使用 : 進行分割的,如果沒有返回值的時候可以省略或者使用Unit,相當於Java的void。
var age:Int = 18
val name:String = "Kotlin"
val person = Person()
使用var來聲明可讀可寫變量,使用val來聲明只讀變量(引用不可變)。
val可以理解為Java中的屬性聲明加上了final關鍵字(將kotlin的字節碼反編譯成Java一看就知道了),其實kotlin是更傾向於推薦使用val來聲明變量,這是一種防禦性的編碼思維模式,目的是減少程序出錯或者變的更加安全。
可以看到實例化Person對象時,並沒有聲明變量類型,這就是Kotlin的「類型推斷」,會自動推斷出是Person類型的變量,而且是不需要Java中的new關鍵字的。
class MyActivity: Activity(), View.OnClickListener {
// 省略
}
一看就懂,不用多說吧。注意加上(),如果你的kotlin類能夠被繼承,需要使用open關鍵字,因為默認是final的:
open class Person {
constructor(age: Int)
var age: Int = 0
}
// 當你的構造函數調用父類的構造函數時,要去掉Person後面的()
class Man: Person {
// 使用super調用父類的構造器
constructor(age: Int): super(age)
}
// 不可空類型
val person: Person
// 可空類型
val person2: Person?
那麼對於可空類型的變量在調用時可以選擇使用:
val person: Person? = null
// 安全調用
person?.age = 18
// 強行調用
person!!.name = "kotlin"
使用?調用符,就算person是null的也不會出現空指針了,相當於Java中的判空了。當然如果你能確認person不會為空,可以使用!!強行調用符
lateinit var person: Person
person = Person()
我們總有場景在聲明的時候不知道賦什麼值,在後面才去賦值的場景,那麼就可以使用lateinit關鍵字。但是只能在以下場景下使用:
if(p is Person) {
p.age = 20
}
val man: Man = Person()
val per: Person = man as Person
is關鍵字類似於Java中的instanceof,判斷是否是什麼類型,判斷不是什麼類型可用!is,可以看到kotlin有個小優化,就是p在條件成立時,不需要再強轉了,直接被認為是Person的類型,進而可以使用Person的API。當你真的需要強轉時可以使用as和as?關鍵字,帶?的在強轉失敗時並不會拋異常,而是返回一個null值
// Person.kt
Person::class
// Man.java
Man::class.java
區別於Java,kotlin要兼容Java,所以獲取Java的class和kotlin的class略有不同,kotlin的class使用::class,而在kotlin中獲取Java的class可以使用::class.java
class Person {
var age: Int? = null
}
// 等價於
class Person {
var age: Int? = null
get() {
return field
}
set(value) {
field = value
}
}
kotlin在聲明非private的屬性時,會默認生成對應的公開的set和get方法,當你在Java中訪問時必須:
Person p = new Person();
p.setAge(20);
不過如果你就要直接訪問age屬性也是可以的,使用@JvmField註解:
// kotlin
class Person: Any {
// kotlin構造函數使用constructor關鍵字
constructor()
// 加上這個註解,編譯器只會生成一個public的屬性,而不生成set和get方法
@JvmField var age: Int = 19
}
// java
public class Test {
private void some() {
Person p = new Person();
p.age = 20;
}
}
open class Person {
constructor(age: Int)
var age: Int = 0
fun test() {
// 會有裝箱拆箱的操作,會影響性能
val ages = arrayOf(14, 15, 16)
// 基本數據類型使用對應的函數,比如intArrayOf()函數避免拆裝箱的過程
val ages2 = intArrayOf(14, 15, 16)
}
}
可以使用arrayOf()來創建數組。對於基本數據類型優先使用對應的函數進行創建。
// 方法在類的外面【包級函數】或者叫【頂層函數】
fun getSomething(): Int {
return 0
}
class Person {}
// 在Java中使用類名+Kt後綴直接訪問
PersonKt.getSomething();
// 在kotlin文件中調用更加方便,只需要導包,不需要加類名
// 但是這種方式並不有利於閱讀,會和類中的函數搞混淆
getSomething()
可以看到我們可以直接在文件裡面聲明函數,然後通過類名+Kt的方式直接調用。這種叫包級函數
object Person {
fun getSomething(): Int {
return 0
}
}
// kotlin中調用
Person.getSomething()
// java中調用
Person.INSTANCE.getSomething();
其實使用object創建類的時候,默認會生成一個單例對象,當我們使用類名來直接調用的時候,其實是通過默認的單例對象進行調用的。本質上和我們java中的靜態方法還是不同的。
class Person {
companion object {
fun getSomething(): Int {
return 0
}
}
}
// kotlin
Person.getSomething()
// java,好麻煩,但是可以使用註解@JvmStatic來讓編譯器編譯成靜態的
Person.Companion.getSomething();
// java 使用註解後就可以在Java中直接調用了
Person.getSomething();
使用companion object(伴生對象)的方式相當於有一個內部類的單例對象,這些通過kotlin的字節碼反編譯成Java文件就可以看出來。看起來比直接使用static關鍵字麻煩多了,那kotlin為啥要去掉static這個關鍵字呢?那得問當初設計kotlin語言的人了,從面向對象的角度來說,這麼設計的確更符合萬物皆對象的理念,因為static只跟類有關,而不是和對象有關。
所以,我們可以看出來使用object貌似和創建默認對象有關係,不錯,比如匿名內部類(本質上就是創建一個對象)
var view = window.decorView
fun test() {
view.setOnClickListener (object : View.OnClickListener{
override fun onClick(v: View?) {
}
})
}
// 當然可以簡寫成下面這樣
fun test() {
view.setOnClickListener {
}
}
可以使用 ${} 來做字符串模板:
val age = 18
val info = "我是一個${age}歲的帥哥"
支持多行字符串,使用三個引號""":
val info = """
hhahha
jaa
sdfjdkjs
jsafjs
""".trimIndent()
判斷數據範圍和switch的使用:
// 如果年齡在10到30(包括30)
if(age in 10..30)
// 使用when取代Java中的switch,並且是支持表達式的
when(age) {
18->{
}
19->{
}
in 20..30-> {
}
}
在 Java 中通過 「 類名.this 例如 Outer.this 」 獲取目標類引用
在 Kotlin中通過「this@類名 例如this@Outer」獲取目標類引用