目錄
前言
今天來學習一下Kotlin這門程序語言,對於一門語言它肯定不是一天能學完的,這個過程會持續一段時間。其實學習程序語言跟我們學習其他語言都是類似的,我們小時候學習中文或者英文的時候是怎樣學習的還記得嗎?是不是首先學習字母,接着學習單詞,然後是語法,最後纔是寫作文,程序語言的學習流程也是一樣的,開始學習基本的數據類型,接着學習程序的控制語句,然後學習函數,最後綜合起來寫一段業務代碼。所以這是一個循序漸進的過程,希望都能做到有始有終!
一、Kotlin簡介
1、Kotlin是一門可以運行在Java虛擬機、Android、瀏覽器上的靜態語言,它與Java 100%兼容,Kotlin除了自己的標準庫之外,大多仍然使用經典的Java集合框架。Kotlin V1.0於2016年2月15日發佈,是第一個官方穩定版本,JetBrains從該版本開始長期向後兼容,在Google I/O 2017中,Google宣佈Kotlin成爲Android的官方開發語言。
2、入門心法之《Hello World》
一套從天而降的掌法那是相當厲害啦,但是一口喫不成個胖子,除非你本來就胖,那我們還是得從基本功練起,先來看個入門內功心法Kotlin——Hello World!在寫代碼之前還得說兩句,因爲我們是在學語言,都是一些很枯燥的東西,所以一定得有耐心,再者就是這裏使用的不是Android Studio這個開發工具,用的是它的老孃Intellij IDEA,而且JetBrains推出Kotlin有一個原因也是希望能夠促進IDEA的銷售,大家學語法的時候因爲並沒有使用在app中,所以最好使用這個工具,操作起來更方便,直接從控制檯看結果。這個工具的下載大家可以到官網上下載,也可以去谷歌找破解版軟件,使用方式熟悉as的應該都知道怎麼用的,下面介紹一下如何創建一個基於gradle的Kotlin的項目,我就不再寫詳細的教程了,這個沒啥說的,直接放個錄屏大家看一下吧:
下面來先寫個HelloWorld吧:
package com.jarchie.cn
fun main(args:Array<String>) {
println("Hello World!")
}
是不是發現跟Java的main函數有些類似,這樣就可以在控制檯輸出一行Hello World!了:
二、Kotlin數據類型
2-1、Boolean類型
我們常說任何事物都具有兩面性,那這個Boolean類型就是隻有兩面性,它只有兩種狀態true和false,它的寫法很簡單:
//Boolean類型的基本寫法
val B1 : Boolean = true
val B2 : Boolean = false
val就是個關鍵字,用來定義常量,B1是常量名,然後冒號後面跟的是類型,等號後面是它的值,在Kotlin裏面一行語句結束不用寫分號。
2-2、Number類型
分類 | 類型 | 位寬 |
---|---|---|
浮點型 | Double | 64 |
Float | 32 | |
整型 | Long | 64 |
Int | 32 | |
Short | 16 | |
字節 | Byte | 8 |
1、Int
它是整型32位字長,定義Int類型數據跟定義Boolean類型的寫法都是類似的,如下所示:
val aInt:Int = 8 //十進制 8
val bInt : Int = 0xff //十六進制 255
val cInt :Int = 0b00000011 //二進制 3
它是個有符號的數,最高位表示符號位,剩下的31位是數值範圍,最大值就是2的31次方減1,最小值就是負的2的31次方,我們來寫段代碼打印一下這幾個數據:
val maxInt: Int = Int.MAX_VALUE
val minInt: Int = Int.MIN_VALUE
fun main(args: Array<String>) {
println("$aInt --- $bInt --- $cInt")
println(maxInt)
println(Math.pow(2.0, 31.0) - 1)
println(minInt)
println(-Math.pow(2.0, 31.0))
}
看一下結果,正是我們猜測的那樣:
2、Long
它是長整型64位字長,就是比Int類型的範圍大一些,沒什麼特別的東西,我們直接來上代碼吧:
val aLong: Long = 123456789098
val bLong: Long = 123 //123通常被認爲是Int類型,但是這裏這樣寫就被認爲是Long類型
val maxLong: Long = Long.MAX_VALUE
val minLong: Long = Long.MIN_VALUE
fun main(args: Array<String>) {
println(123L) //單獨打印123,那麼它就是整型,如果想讓它是長整型,需要在後面加個L
println(maxLong)
println(minLong)
println(Math.pow(2.0, 63.0) - 1)
println(-Math.pow(2.0, 63.0))
}
結果如下圖所示:
這裏需要注意理解的東西我在代碼中寫了註釋,大家看一下理解了就行了。
3、Float
它是32位浮點型,也稱單精度類型,聲明Float類型數據的時候如果你直接這樣寫:val a:Float = 2.0,這時編譯器會告訴你它是不可以的,在Kotlin中這樣直接寫2.0它其實是雙精度類型的,那我們應該怎麼寫呢?需要在後面加個F,如下代碼所示:
val aFloat: Float = 2.0F //需要加f
val bFloat: Float = 1E3f //10的三次方
val maxFloat: Float = Float.MAX_VALUE
val minFloat: Float = Float.MIN_VALUE
fun main(args: Array<String>) {
println("$aFloat $bFloat")
println(maxFloat)
println(minFloat)
}
結果如下:
這裏有個問題不知道大家發現沒有,這個最小值居然是個正數,驚不驚喜意不意外,點到源碼裏面查看一下:
看註釋意思:保持Float的最小正非零值的常數,那我們該怎麼改呢?應該取-Float.MAX_VALUE,負的最大值。
注意:Float類型因爲是浮點型,它不像整型那樣精確,所以在使用它的時候可能會有精度問題,如果涉及到金錢方面的程序,最好不要使用Float類型。
4、Double
它是雙精度浮點型型64位字長,表示的範圍比Float大很多,因爲是指數級的增長,其餘的都很類似,直接上代碼吧:
val aDouble: Double = 3.0
val bDouble: Double = 3.1415926
val maxDouble: Double = Double.MAX_VALUE
//val minD:Double = Double.MIN_VALUE //最小的非零正數,並非最小值
val minDouble: Double = -Double.MAX_VALUE //將最大值取反,得到最小值
fun main(args: Array<String>) {
println("$aDouble $bDouble")
println(maxDouble)
println(minDouble)
}
結果如下:
5、Short
它是短整型16位字長,平時開發中可能很少用到,這裏也提一下吧,很簡單,就是取值範圍比Int小一些,直接上代碼:
val aShort: Short = 127
val maxShort: Short = Short.MAX_VALUE
val minShort: Short = Short.MIN_VALUE
fun main(args: Array<String>) {
println(aShort)
println(maxShort)
println(minShort)
}
結果如下:
6、Byte
它是字節類型8位字長,一個字節就是8位,地球人都知道,由於字長較短,所以它能表示的數據範圍也比較小,看代碼:
//val byte:Byte = 235 //編譯器會報錯,這個整型的字面量大了,超出範圍了,
// 所以如果要用整型的字面量給Byte類型賦值,因爲它是有符號的,所以
//最大值肯定是2的7次方-1,那就是127,超出這個值肯定會報錯
val maxByte: Byte = Byte.MAX_VALUE
val minByte: Byte = Byte.MIN_VALUE
fun main(args: Array<String>) {
println(maxByte)
println(minByte)
}
它的數據範圍這裏也在代碼中作了解釋,看下結果:
對於Long、Int、Short、Byte等幾種類型單從上面的例子中可以看到它們都是整數,在表格中爲什麼我們單獨將Byte作爲一類呢?是因爲實際開發中我們並不直接用Byte表示一個整數,而是把它作爲數據流進行讀寫操作,作爲一個二進制的數據操作。
2-3、Char類型
它是雙字節16位的Unicode字符,它表示一個字符,對應Java中的Character,一個字符可以是一個字也可以是一個符號,字符用單引號''引起來,例如:'a'、'+','\n'等,來看代碼:
val aChar: Char = '0'
val bChar: Char = '國'
//val cChar: Char = '\u000f' // \u表示的就是Unicode,後面的000f是一個Unicode編碼
val cChar: Char = '\n' //換行符
fun main(args: Array<String>) {
println(aChar)
println(bChar)
println(cChar)
}
結果如下:
像上面'\n'這樣的字符其實就是轉義字符,下面一起來看幾個常用的轉義字符:
轉義字符 | 含義 |
---|---|
\t | 製表符 |
\b | 光標後退一個字符 |
\n | 回車 |
\r | 光標回到行首 |
\' | 單引號 |
\" | 雙引號 |
\\ | 反斜槓 |
\$ | 美元符號,Kotlin支持美元符號開頭的字符串模板 |
2-4、拆箱裝箱
先來看一段Java代碼:
public class HelloWorldJava {
public static void main(String[] args) {
int aInt = 5; //基本類型
Integer aInteger = 5; //裝箱類型
}
}
在Java中int是基本類型,Interger是裝箱類型,在Kotlin中其實並沒有作這樣的區分,所有的整數都叫int,kotlin中的int實際上是Java中的基本類型int和裝箱類型Integer的合體,在需要的時候編譯器會自動幫我們選擇到底是用基本類型的int還是裝箱類型的Integer,類似的像長整型、單精度浮點型、雙精度浮點型 都有這樣的情況出現,在kotlin中不再區分裝箱和非裝箱類型。
2-5、基礎數據類型轉換
在Java中,把一個int類型的值賦給long類型的變量是沒有任何問題的,因爲整型值表示的數據範圍比長整型的要小,但是在kotlin中這種隱式轉換是不被支持的,比如下面的這兩行代碼,必須要顯示調用toLong()方法進行轉換:
val a: Int = 5
//val b: Long = a //編譯會報錯
val b: Long = a.toLong()
2-6、字符串
1、字符串本質上就是'一串'Char,字符串可以直接使用雙引號“”引起來定義,也可以使用字符進行構造,舉個栗子:
val s1: String = "Hello Kotlin"
val s2: String = String(charArrayOf('H', 'e', 'l', 'l', 'o', ' ', 'K', 'o', 't', 'l', 'i', 'n')) //使用字符構造
fun main(args: Array<String>) {
println(s1)
println(s2)
}
結果很明顯,都是輸出一段Hello Kotlin:
2、在Kotlin中如何比較字符串呢?有些人可能會想到java中的等號了,在kotlin中使用“==”比較內容,等同於equals()方法,使用“===”比較對象,寫段代碼驗證下:
fun main(args: Array<String>) {
println(s1 == s2) //這個等同於equals方法
println(s1 === s2) //這個比較的是引用地址
}
結果如下,跟前面說的是一致的:
3、字符串模板
在Kotlin中有個字符串模板,在字符串中使用“$”美元符號後面加上某個變量名可以引用某個變量值,例如:
val aNum: Int = 1
val bNum: Int = 1
fun main(args: Array<String>) {
println("$aNum + $bNum = ${aNum + bNum}")
}
結果如下:
4、轉義字符的使用
val money: Int = 100
fun main(args: Array<String>) {
println("Hello \"Jarchie\"") //Hello "Jarchie"
println("$money") //1000
println("$$money") //$1000
println("\$money") //$money
}
結果也很明顯了:
5、原始字符串
使用"""aaa"""三個引號引起來,裏面的內容會原封不動的輸出,舉個例子:
val rawString:String = """aaa
\t \n
aaa"""
fun main(args: Array<String>) {
println(rawString)
}
輸出結果如下,它不會做任何的轉義:
三、類和對象
3-1、什麼是類?
本篇內容只是簡單的介紹一下類的概念和基本使用方法,這個本來是打算在寫面向對象那部分再說的,後來想了想,還是得先說一下。類是一個抽象的概念,它是具有某些特徵事物的概括,不特定指代任何一個具體的事物。舉個栗子:我們平時日常生活中的人、車子、書本等,像上面介紹過的數、字符串也是類。
類的定義(寫法):class <類名> (構造方法){<成員>}
3-2、什麼是對象?
對象是一個具體的概念,與類是相對的,它是描述某一種類的具體的個體,舉個栗子:某個人、某輛車(我的凱迪拉克,想象中。。。)、我的《安卓開發藝術探索》這本書。
3-3、類和對象的關係
- 一個類通常可以有很多個具體的對象
- 一個對象本質上只能從屬於一個類
- 某一個具體的人,他是老師,但本質上還是屬於人這一類,從這裏可以看出類和對象是1...n也就是一對多的關係
- 對象也經常被稱作“類的對象”或者“類的實例”
3-4、類的繼承
- 提取多個類的共性得到一個更加抽象的類,我們稱之爲父類,
- 子類擁有父類的一切特徵,
- 子類也可以自定義自己的特徵,
- 所有的類都最終繼承自Any
3-5、代碼示例
說個程序裏面經常開的玩笑:你有對象嗎?沒有我給你new一個,那我現在就給你new一個對象了哈,
//constructor()是構造方法,因爲只有一個構造方法主構造方法,所以constructor可以省略不寫,
// 如果類中沒有定義其他成員的話{}也可以省略
class 對象 constructor(var 性格:String,var 長相:String,var 身材:String){
init { //構造方法的方法體,在每次創建對象的時候都會調用這個方法體
println("new了一個對象,她性格$性格,長相$長相,身材$身材")
}
}
fun main(args:Array<String>) {
val 你對象:對象 = 對象("溫柔","甜美","苗條")
}
結果如下:
那現在我們來想一下哈,對象是new完了,那這個時候來了一個她的愛慕者,我們索性成爲單身狗,這個單身狗同樣的是有這麼幾個屬性,那我們想要new一個單身狗,我們是不是還得再創建一個單身狗的類呢?其實有經驗的大家應該能想到了,他們是有共性的,我們可以再做一層抽象,抽出來一個人的類,讓這個單身狗和你的對象都去繼承它,我們來看一下代碼:
open class 人(var 性格: String, var 長相: String, var 身材: String){
init {
println("new了一個${this.javaClass.simpleName},Ta性格$性格,長相$長相,身材$身材")
}
}
class 對象(性格: String, 長相: String, 身材: String) : 人(性格, 長相, 身材)
class 單身狗(性格: String, 長相: String, 身材: String) : 人(性格, 長相, 身材)
fun main(args: Array<String>) {
val 你對象: 對象 = 對象("溫柔", "甜美", "苗條")
val singleDog: 單身狗 = 單身狗("孤僻", "奇醜", "矮小")
println(你對象 is 人) //Kotlin中的is相當於Java中的instanceof
}
這樣寫是不是簡單了一些,來看下結果:
代碼中我們定義了一個“人”的類,然後讓“對象”繼承了“人”,中間使用了一個“:”冒號,這就是繼承的寫法了,這樣對象就擁有了人的屬性,對象就是人的子類,人就是對象的父類。在Kotlin中所有的類都直接或間接的是"Any"這個類的子類,不信的可以看下源碼:這行註釋的意思就是:Kotlin類層次結構的根。每個Kotlin類都有[Any]作爲超類。
四、空類型和智能類型轉換
4-1、空類型
在Java中,如果遇到對象爲null的情況,會給我們返回一個空指針異常,導致我們的程序直接Crash。在Kotlin中任意類型都有可空和不可空兩種,具體的情況見下方表格:
val notNull:String = null //錯誤,不能爲空,編譯器報錯 |
val nullable:String? = null //正確,可以爲空,在類型後面加"?"表示可空 |
notNull.length //正確,不爲空的值可以直接使用 |
nullable.length //錯誤,可能爲空,編譯器報錯,不能直接獲取長度 |
nullable!!.length //正確,強制認定nullable不可空 |
nullable?.length //若nullable爲空,則返回空 |
這裏舉個栗子,看的更明白點:
fun getName(): String? {
return null
}
fun main(args: Array<String>) {
val name1 = getName()
println(name1?.length)
val name:String? = "Hello Kotlin"
println(name!!.length)
val name2:String = getName()?:return
println(name2.length)
println("這句話不會被打印,因爲它不會執行到這裏")
}
結果如下:
4-2、類型轉換
這裏介紹三種:
第一種:Java Style類型轉換
val sub:SubClass = parent as SubClass 類似於Java的類型轉換,失敗則拋異常
第二種:安全類型轉換
val sub:SubClass? = parent as? SubClass 如果轉換失敗,返回null,不拋異常
第三種:智能類型轉換
if(parent is SubClass) parent.<子類的成員> 編譯器儘可能的推導類型,遠離無用的類型轉換
if(nullable != null) nullable.length 正確!因爲我們確認nullable不爲空!
還是同樣的寫段代碼來加深印象吧:
package com.jarchie.kotlin.basic
open class Parent
class Child : Parent() {
fun getName():String{
return "Child"
}
}
fun main(args: Array<String>) {
val parent: Parent = Child() //強轉
if (parent is Child) {
println(parent.getName()) //智能轉換,無需強轉
}
val string: String? = "Hello"
if (string is String) //或者 if(string != null)
println(string.length)
val parents:Parent = Parent()
val child :Child? = parents as? Child //不加?會拋出異常
println(child)
}
來看下結果,看轉換失敗的也不會拋異常了,給我們返回個null:
五、包(Package)
- 它是命名空間
- 包的聲明必須在非註釋代碼的第一行
- 類的全名:-com.jarchie.cn.basic.對象
這個跟Java中的包挺像的,不多說了,使用時導入對應的類的全名即可,比如下面這個:
六、區間(Range)
- 一個數學上的概念,表示範圍
- ClosedRange的子類,IntRange最常用
- 基本寫法:0..100表示[0,100]; 0 until 100表示[0,100); i in 0..100判斷i是否在區間[0,100]中
舉個栗子:
val range1: IntRange = 0..1024 //[0.1024]
val range2: IntRange = 0 until 1024 //[0,1024) 等同於[0,1023]
val emptyRange: IntRange = 0..-1
fun main(args: Array<String>) {
println(emptyRange.isEmpty())
println(range1.contains(1024))
println(1024 in range1)
println(range2.contains(1024))
// for (number in range1) { //迭代數據
// print("$number,")
// }
}
結果如下:
七、數組
1、什麼是數組
對應英文單字Array,跟數沒啥關係,主要是組,它是一系列對象。
2、使用方式
基本寫法:val array:Array<String> = arrayOf(...)
基本操作:
- print array[i] 輸出第i個成員
- array[i] = "China" 給第i個成員賦值
- array.length 數組的長度
3、基本類型的數組
爲了避免不必要的裝箱和拆箱,基本類型的數組是定製的
Java | Kotlin |
---|---|
int[] | IntArray |
short[] | ShortArray |
long[] | LongArray |
float[] | FloatArray |
double[] | DoubleArray |
char[] | CharArray |
好了,知識點說完了,我們再來通過一段代碼來加深下理解(注意代碼中的“對象”類要複寫toString()方法):
package com.jarchie.kotlin.array
import com.jarchie.kotlin.basic.對象
val arrayOfInt: IntArray = intArrayOf(1, 2, 3, 4)
val arrayOfChar: CharArray = charArrayOf('a', 'b', 'c')
val arrayOfString: Array<String> = arrayOf("我", "愛", "China")
val arrayOf對象: Array<對象> = arrayOf(對象("美女1號"), 對象("美女2號"), 對象("美女3號"))
fun main(args: Array<String>) {
println(arrayOfInt.size) //獲取數組長度
for (char in arrayOfChar) { //遍歷數組
println(char)
}
println(arrayOf對象[1])
arrayOf對象[1] = 對象("美女100號") //獲取數組中某個下標的元素值並修改它的值
println(arrayOf對象[1])
println(arrayOfChar.joinToString("")) //將字符數組中的元素按照某種規則連接起來
println(arrayOfInt.slice(1..2)) //字符串切片,這裏我們獲取整型數組的第1,2兩位的元素
}
來看一下結果,看看你寫對了嗎:
寫到這裏已是深夜了,這一部分的內容就暫時寫這麼多,有不對的歡迎指正,下一篇是Kotlin的程序結構,敬請期待吧!
各位晚安!