Kotlin學習:基礎語法姿勢

最近在學習kotlin,隨便總結一下知識點。有興趣的同學可以好好看看哦,每一段都有代碼示例!!!

一、基礎知識

1、聲明變量

fun main(){
    //變量
    var a:Int = 1;
    //常量
    val b:Int = 2;
}

這裏a、b表示變量的名字,冒號後面表示變量的類型。用val表示常量。

fun main(){
    //不可爲空的類型
    var str1:String = "aaa";
    //可以爲空的類型
    var str2:String? = null;
    str1 = str2 
    str2 = str1
}

用?表示這個變量可以爲null,如果不加表示不可爲空,編譯會報錯。str1 = str2這個是無法通過編譯的。

2、函數相關

fun printLen(str:String):String{
	printLn("$str")
	return str;
}

Kotlin中的函數可以不放在類裏面,單獨提出來。實際上編譯後的字節碼文件依然是放在一個類裏面。printLn("$str")這個$符號,表示這個變量可以放在字符串裏,我們就減少了字符串的拼接。

3、與java中的不同

(1)內部類

class Main{
   object Test {
       fun sayMessage(msg: String) {
           println(msg)
       }
   }
    fun main(){
        println(Test.sayMessage("aaa"))
    }
}

Test是一個匿名內部類,在java中,匿名內部類會被單獨編譯成一個class文件,在外部類的內部有一個單例的對象。

java:
    Test.INSTANCE.sayMessage("aaa")
kotlin:
    Test.sayMessage("aaa")

這其實也是kotlin創造單例對象的方法。

(2)字節碼對象

class Main{
   object Test {
       fun sayMessage(msg: String) {
           println(msg)
       }
   }
    fun main(){
        getName(JavaBean::class.java)
        getName(KotlinBean::class)
    }
    fun getName(clazz:Class<JavaBean>){
        println(clazz.simpleName)
    }
    fun getName(clazz:KClass<KotlinBean>){
        println(clazz.simpleName)
    }
}

public class JavaBean {
}


class KotlinBean

在kotlin中獲得java的字節碼xx::class.java,對於kotlin本身的對象類型是KClass傳入的是xx::class。

(3)解決關鍵字衝突

public class JavaBean {
    
    public static int in = 1;
}

class Main{
    fun main(){
        println(JavaBean.`in`)
    }
}

in 在java中聲明爲了變量,但是在Kotlin中確是關鍵字,所以呢,要用``來處理。同時``可以將不合法字符變成合法的,比如:fun `123`{}。

4、kotlin與java互調產生的問題

kotlin 沒有封裝類,調用java方法,只會執行基本數據類型方法

public interface TestInterface {

    void putNum(int num);

    void putNum(Integer num);
}

public class Impl  implements TestInterface{

    public static TestInterface test = new Impl();
    @Override
    public void putNum(int num) {
        System.out.println("int");
    }

    @Override
    public void putNum(Integer num) {
        System.out.println("Integer");
    }
}
fun main() {
    Impl.test.putNum(123);
}

打印輸出的是int。這就是由於kotlin中沒有Integer,所以把兩個方法併爲一個方法了,如果kotlin中實現接口,那麼只需要重寫一個方法就可以了。

kotlin 類型空值敏感

當kotlin調用java方法的時候,課程會返回一個null,如果我們不處理程序會有安全問題。

public class Temp {
    public static String format(String str){
        return str.isEmpty() ? null : str;
    }
}

fun main() {
    function("")
}
fun function(str:String){
    val fmt1 = Temp.format(str);
    println(fmt1)
    val fmt2:String = Temp.format(str);
    val fmt3:String? = Temp.format(str);
    println(fmt3?.length)

}

fmt2會直接在運行的時候報錯,因爲format方法返回的就是null值,fmt1是null。fmt3纔是安全的所以要用?設置成可控類型的,這樣纔是安全的。

kotlin 中沒有靜態變量和靜態方法

在java中調用kotlin方法

class StaticDemo{

    object Test{
        fun sayMessage(msg:String){
            println(msg)
        }
    }
}
public class Main1 {
    public static void main(String[] args) {
        StaticDemo.Test.INSTANCE.sayMessage("aaa");
    }
}

那我們能不能在java中像調用靜態方法一樣方便呢?就是把INSTANCE去掉?答案是可以的

class StaticDemo{

    object Test{

        @JvmStatic
        fun sayMessage(msg:String){
            println(msg)
        }
    }
}

public class Main1 {
    public static void main(String[] args) {
        StaticDemo.Test.sayMessage("aaa");
    }
}

5、判斷相等

kotlin             java
a == b             a.equals(b)
a === b            a == b

二、函數和Lambda閉包

1、函數的特性語法

//標準寫法
fun echo(name:String){
    println("name:$name")
}
//攜帶默認參數
fun echo(name:String = "xiaoming"){
    println("name:$name")
}
//簡易寫法,函數中只有一個語句可以搞
fun echo(name:String) = println("name:$name")

默認參數,在java中調用也需要傳參數,在kotlin中不用

2、嵌套函數

fun main() {
    function()
}
fun function(){
    var str ="hello world"
    fun say(count:Int = 10){
        println(str)
        if(count > 0){
            say(count - 1)
        }
    }
    say()
}

用途:(1)在某些條件下,觸發遞歸函數(2)不希望被外部函數訪問的函數

!!!不推薦使用

3、擴展函數

class Main{

}
fun Main.aaa() = print("aaa")
fun main() {
    Main().aaa();
}

對一個類的方法進行擴展,類名+ . +方法名。在編譯的時候會編譯到類裏面。

擴展函數是靜態的,不具備運行時的多態!

一般應用於第三方的sdk或者系統類。

4、Lambda閉包語法

lambda:

//java8中
 public static void main(String[] args) {
        Thread thread = new Thread(() -> System.out.println("aaa"));
 }
//kotlin中
fun main() {
    var thread = Thread({ -> println("aaaa")})
    thread.start()
}

如果lambda是沒有參數的可以更加簡化一點:

 var thread1 = Thread({ })
 var thread2 = Thread(){}
 var thread3 = Thread{}

閉包語法:

//lambda閉包
var print = {
    name:String ->  println("name:$name")
}
fun main() {
   print("aaa")
}

最多傳入22個參數

5、高階函數

將函數作爲參數傳遞給另一個函數...。

fun onlyIf(isDebug:Boolean,block:() -> Unit){
    if(isDebug) block();
}
fun main() {
   onlyIf(true){
       println("打印日誌")
   }
}
fun onlyIf(isDebug:Boolean,block:() -> Unit){
    if(isDebug) block();
}
fun main() {
    val runnable:Runnable = Runnable {
        print("runnable::run")
    }
    var funn:() -> Unit
    funn = runnable::run
    onlyIf(true,funn)
}

這裏面首先創建了一個對象Runnable。然後有一個lambda函數聲明,利用::將對象中方法拿出來,賦值給funn,然後再調用。

6、內聯函數

inline fun onlyIf(isDebug:Boolean,block:() -> Unit){
    if(isDebug) block();
}
fun main() {
    val runnable:Runnable = Runnable {
        print("runnable::run")
    }
    var funn:() -> Unit 
    funn = runnable::run
    onlyIf(true,funn)
}

kotlin的Lambda是一個匿名對象。可以使用inline修飾方法,在編譯的時候會拆解方法的調用爲語句調用,進而減少創建不必要的對象。

三、類和對象

1、構造函數

open class Father{

}

class Son:Father(){

}

kotlin類中默認有public final修飾符,默認不允許繼承,如果想要繼承,必須要用open修飾。繼承用:,可以繼承一個父類或者多個接口。

open class Father(var num:Int){
    init {
        print("father")
    }
    open fun printClass():Unit{
        println("printClass")
    }
}
open interface FatherInterface{
    fun printInterface()
}

class Son(var a:Int):Father(a),FatherInterface{
    override fun printInterface() {
    }
    
    override fun printClass(){
    }
}

這裏面類名後面的()就是構造函數。如果想要在構造函數中執行某些邏輯就寫在init方法。override表示重寫方法。

多級構造函數

class Test(str:String){
    var str:String = str;
    var num:Int = 0;
    var doub:Double = 0.0;

    constructor(str:String,num:Int):this(str){
        this.num = num;
    } 
    constructor(str:String,num:Int,doub:Double):this(str,num){
        this.doub = doub;
    }
}

利用constructor聲明多級構造函數,this()表示調用主構造函數。次級構造函數必須調用主構造函數。

2、訪問修飾符

//前三個跟java的一樣
private
protected
public
//這個指在模塊內能夠訪問,例如module
internal

3、伴生對象

class StringUtils{

    companion object {
        fun isEmpty(str:String):Boolean{
            return "" == str
        }
    }
}

fun main() {
    println(StringUtils.isEmpty(""))
    println(StringUtils.isEmpty("aa"))
}

有點像java靜態方法,跟我們上面說的@JvmStatic註解有點像,在編譯的時候爲我們創建了一個靜態內部對象。

4、單例類

class Single constructor(){
    companion object {
        fun get():Single{
            return Holder.instance
        }
    }
    private object Holder{
        var instance = Single();
    }
}

 

5、類的動態代理

interface Animal{
    fun bark();
}

class Dog:Animal{
    override fun bark() {
        println("wang")
    }
}
class Zoo(animal: Animal):Animal by animal

fun main() {
    Zoo(Dog()).bark()
}

輸出wang,如果重寫了bark方法,就不會代理了。kotlin中編譯的時候用的是靜態代理,要比java中的效率高。

6、kotlin特有的類

數據類:

data class User(var id:Long,var name:String)

自動提供toString、equal、hashcode、getter、setter方法。並且類是final。

枚舉類:

enum class Command{
    A,B,C,D
}
//下面相當於switch去匹配
fun exec(command: Command) = when (command){
    Command.A -> {}
    Command.B -> {}
    Command.C -> {}
    Command.D -> {}
}

超級枚舉:密閉類:

sealed class SuperCommand{
    object A:SuperCommand()
    object B:SuperCommand()
    object C:SuperCommand()
    object D:SuperCommand()
}

fun exec(command: SuperCommand) = when (command){
    SuperCommand.A -> {}
    SuperCommand.B -> {}
    SuperCommand.C -> {}
    SuperCommand.D -> {}
}

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章