Kotlin 入門學習筆記

PhilCoulson發表於2018-01-03

以下內容純粹為本人學習期間總結,如有錯誤之處煩請指正不勝感激?

此次學習分享的內容均是Kotlin入門基礎語法;協程,Anko,擴充套件屬性等等還沒涉及到

筆記主要採用和Java進行對比的模式來學習和總結,便於理解和對比學習,增加直觀感受,提升掌握Kotlin的學習效率

繼承

  • Java
class A extends B { }
複製程式碼
  • Kotlin
class A : B() {}
複製程式碼

介面

  • Java
class A implements B, C {}
複製程式碼
  • Kotlin
class A : B, C {}
複製程式碼

override

Java 中是註解。重寫父類方法,實現介面方法 在Kotlin中成了類似關鍵字的東西。重寫和實現自帶了,不再是註解

  • Java
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
   super.onCreate(savedInstanceState);
   setContentView(R.layout.activity_main);
}
複製程式碼
  • Kotlin
override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.activity_main)
}
複製程式碼

Object 類

  • JavaObject是所有型別的頂級父類
  • Kotlin中並沒有Object,取而代之的是Any(),意義和Java中的Object一樣。注意此處指的是大寫OObject,非小寫oobject

結紮關鍵字

  • JavaKotlin都不能繼承自結紮類
  • Java中用final修飾的類不可被繼承,並且Java中的類不宣告為final的話則預設可被繼承
  • Kotlin中則和Java相反,Kotlin中的類預設是被結紮的,不可被繼承,除非使用了open關鍵字
  • Kotlin中如果某個類被宣告為abstract,則不需要使用open進行修飾了,預設已經帶上

例項化物件

  • Java
Person person = new Person(bug, 需求);
複製程式碼
  • Kotlin
var person = Person(bug, 需求)
複製程式碼

列印日誌

  • Java
System.out.print("列印日誌");
System.out.println("列印日誌");
複製程式碼
  • Kotlin
print("列印日誌")
println("列印日誌")
複製程式碼

常量與變數

  • Java
String name = "Hello Java";
final String name = "Hello 結紮過的 Java";
複製程式碼
  • Kotlin
var name = "Hello Kotlin"
val name = "Hello 結紮過的 Kotlin"
複製程式碼

null宣告

  • Java
String otherName;
otherName = null;
複製程式碼
  • Kotlin
//在型別後面跟英文問號代表此變數可空
var otherName : String?
otherName = null
複製程式碼

空判斷

  • Java
if (text != null) {
    int length = text.length();
}
複製程式碼
  • Kotlin
text?.let {
    val length = text.length
}
// 簡單寫法
val length = text?.length
複製程式碼

字串拼接

  • Java
String firstName = "ja";
String lastName = "va";
String message = "名字是: " + firstName + " " + lastName;
複製程式碼
  • Kotlin
val firstName = "Ko"
val lastName = "tlin"
val message = "名字是: $firstName $lastName"
複製程式碼

換行

  • Java
String text = "第一行\n" +
              "第二行\n" +
              "第三行";
複製程式碼
  • Kotlin
//又叫多行文字字串
val text = """
        |第一行
        |第二行
        |第三行
        """.trimMargin()
//trimMargin()方法是Kotlin自己的,用於替換掉字串中的指定符號並且格式化多行文字字串,使之居左對齊。點選檢視原始碼可知預設值是"|",所以我們可以依照自己的需求來進行替換

val text = """
        >First Line
        |Second Line
        >Third Line
        """.trimMargin(">")
//這樣就只會替換掉第一行和第三行前面的大於符號並且將第一行第三行居左對齊,第二行無變化
複製程式碼

三目運算子

  • Java
String text = x > 5 ? "x > 5" : "x <= 5";
複製程式碼
  • Kotlin
val text = if (x > 5)
              "x > 5"
           else "x <= 5"

//簡單寫法
var s: String? = null
var text = s ?: "空了"  //s為空麼?不為空返回自己,為空返回"空了"
複製程式碼

操作符

  • java
final int andResult  = a & b;
final int orResult   = a | b;
final int xorResult  = a ^ b;
final int rightShift = a >> 2;
final int leftShift  = a << 2;
複製程式碼
  • Kotlin
val andResult  = a and b
val orResult   = a or b
val xorResult  = a xor b
val rightShift = a shr 2
val leftShift  = a shl 2
複製程式碼

型別判斷和轉換 (宣告式)

  • Java
if (object instanceof Car) {
}
Car car = (Car) object;
複製程式碼
  • Kotlin
if (object is Car) {
}
var car = object as Car
複製程式碼

型別判斷和轉換 (隱式)

  • Java
if (object instanceof Car) {
   Car car = (Car) object;
}
複製程式碼
  • Kotlin
if (object is Car) {
   var car = object // smart casting
}
複製程式碼

多重條件

  • Java
if (score >= 0 && score <= 300) { }
複製程式碼
  • Kotlin
if (score in 0..300) { }
複製程式碼

更靈活的case語句

  • Java
int score = // some score;
String grade;
switch (score) {
    case 10:
    case 9:
        grade = "Excellent";
        break;
    case 8:
    case 7:
    case 6:
        grade = "Good";
        break;
    case 5:
    case 4:
        grade = "OK";
        break;
    case 3:
    case 2:
    case 1:
        grade = "Fail";
        break;
    default:
        grade = "Fail";
}
複製程式碼
  • Kotlin
var score = // some score
var grade = when (score) {
    9, 10 -> "Excellent"
    in 6..8 -> "Good"
    4, 5 -> "OK"
    in 1..3 -> "Fail"
    else -> "Fail"
}
複製程式碼

for迴圈

  • Java
for (int i = 1; i <= 10 ; i++) { }

for (int i = 1; i < 10 ; i++) { }

for (int i = 10; i >= 0 ; i--) { }

for (int i = 1; i <= 10 ; i+=2) { }

for (int i = 10; i >= 0 ; i-=2) { }

for (String item : collection) { }

for (Map.Entry<String, String> entry: map.entrySet()) { }
複製程式碼
  • Kotlin
for (i in 1..10) { }

for (i in 1 until 10) { }

for (i in 10 downTo 0) { }

for (i in 1..10 step 2) { }

for (i in 10 downTo 0 step 2) { }

for (item in collection) { }

for ((key, value) in map) { }
複製程式碼

更方便的集合操作一

  • Java
final List<Integer> listOfNumber = Arrays.asList(1, 2, 3, 4);

final Map<Integer, String> keyValue = new HashMap<Integer, String>();
map.put(1, "Java");
map.put(2, "Kotlin");
map.put(3, "Scala");
map.put(4, "Swift");

// Java 9
final List<Integer> listOfNumber = List.of(1, 2, 3, 4);

final Map<Integer, String> keyValue = Map.of(1, "Java",
                                             2, "Kotlin",
                                             3, "Scala",
                                             4, "Swift");
複製程式碼
  • Kotlin
val listOfNumber = listOf(1, 2, 3, 4)
val keyValue = mapOf(1 to "Java",
                     2 to "Kotlin",
                     3 to "Scala",
                     4 to "Swift")
複製程式碼

更方便的集合操作二

  • Java
List<String> list = new ArrayList();
list.add("Java");
list.add("Kotlin");
list.add("Scala");
list.add("Swift");

Map<Integer, String> map = new HashMap();
map.put(1, "Java");
map.put(2, "Kotlin");
map.put(3, "Scala");
map.put(4, "Swift");
複製程式碼
  • Kotlin
var list = mutableListOf<String>()
list.add("Java")
list.add("Kotlin")
list.add("Scala")
list.add("Swift")

var map = mutableMapOf<Int, String>()
map.put(1, "Java")
map.put(2, "Kotlin")
map.put(3, "Scala")
map.put(4, "Swift")

複製程式碼

遍歷

  • Java
// Java 7 和以前
for (Car car : cars) {
  System.out.println(car.speed);
}

// Java 8+
cars.forEach(car -> System.out.println(car.speed));

// Java 7 和以前
for (Car car : cars) {
  if (car.speed > 100) {
    System.out.println(car.speed);
  }
}

// Java 8+
cars.stream().filter(car -> car.speed > 100).forEach(car -> System.out.println(car.speed));
複製程式碼
  • Kotlin
cars.forEach {
    println(it.speed)
}

cars.filter { it.speed > 100 }
      .forEach { println(it.speed)}
複製程式碼

方法定義

  • Java
void doSomething() {
   
}

void doSomething(int... numbers) {
   
}
複製程式碼
  • Kotlin
fun doSomething() {
   
}

fun doSomething(vararg numbers: Int) {
   
}
複製程式碼

帶返回值的方法

  • Java
int getScore() {
  
   return score;
}
複製程式碼
  • Kotlin
fun getScore(): Int {
   
   return score
}

//可直接在方法後返回
fun getScore(): Int = score
複製程式碼

無結束符號

  • Java
int getScore(int value) {
   
    return 2 * value;
}
複製程式碼
  • Kotlin
fun getScore(value: Int): Int {
   
   return 2 * value
}

//可直接在方法後返回
fun getScore(value: Int): Int = 2 * value
複製程式碼

constructor 構造器

  • Java
public class Utils {

    private Utils() { 
     
    }
  
    public Utils(Int i ,String s){
      
	}
    
}
複製程式碼
  • Kotlin
class Utils constructor(i: Int, s: String) {
	//這種方式的構造器是顯示構造器,宣告類的時候定好構造方法,例項化的時候必須按照引數列表進行例項化
  var utils = Utils(1, "")
}

class Utils (i: Int, s: String) {
	//上面的方式可省略 constructor 關鍵字
  var utils = Utils(1, "")
}

class Utils {
    constructor(i: Int, s: String)
    //上面同樣可以寫成這種樣子,建構函式單獨寫進類裡面
  var utils = Utils(1, "")
}


class Utils private constructor(i: Int, s: String) {
	//如果 constructor 前面有修飾符,則不能省略
  var utils = Utils()
}

class Utils private constructor() {
    constructor(i: Int, s: String) : this() {
        //這種宣告表示我們有一個私有的構造方法,無參的,也可以有參,自己定義就好;然後我們公開了一個有參的構造方法供外部進行例項化
      var utils = Utils(1, "")
    }
}

class Utils constructor(i: Int = 2, s: String = "") {
	//如果構造方法中給定了預設值,那麼在例項化物件的時候可以不傳入引數,不傳的話例項化出來的物件預設引數就是構造方法中的引數
  var utils = Utils()
  var utils = Utils(1)
  var utils = Utils("")
  var utils = Utils(1, "")
}

class Utils constructor(i: Int, s: String = "") {
	//但如果引數列表中有那種沒有給定值的變數時,例項化時必須要將他們都傳入構造方法
  var utils = Utils(1)
  var utils = Utils(1, "")
}


//引申內容,方法過載,注意和下面的 Kotlin 擴充套件函式區別開
class MainActivityKotlin {
  
  override fun onCreate(saveInstance: Bundle?) {
      super.onCreate(savedInstanceState)
        makeToast()
        makeToast("test")
        makeToast(time = Toast.LENGTH_LONG)
        makeToast("test", Toast.LENGTH_LONG)
        makeToast(msg = "test", time = Toast.LENGTH_LONG)
    }

    fun makeToast(msg: String = "msg", time: Int = Toast.LENGTH_SHORT) {
        Toast.makeText(this, msg, time).show()
    }
}
複製程式碼

Kotlin 擴充套件函式

  • Kotlin
//擴充套件函式一般用在工具類的封裝上,可以對現有的函式在不繼承的情況下進行擴充套件
//object 宣告下面會講到
//擴充套件函式一般寫法是,fun 關鍵字 加上要擴充套件的類的類名,以及方法名
object Utils {

    fun Activity.makeToast(msg: String = "msg", time: Int = Toast.LENGTH_SHORT) {
        Toast.makeText(this, msg, time).show()
    }
}

//呼叫時如下
//從呼叫處的包引入`import com.danlu.kotlindemo.Utils.makeToast`可以知道,擴充套件函式實際上是以靜態被引入的,事實上它是靜態解析的
//除了擴充套件函式,還有擴充套件屬性
class MainActivityKotlin : AppCompatActivity() {
    
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        makeToast()
        makeToast("test")
        makeToast(time = Toast.LENGTH_LONG)
        makeToast("test", Toast.LENGTH_LONG)
        makeToast(msg = "test", time = Toast.LENGTH_LONG)

    }
}
複製程式碼

Get Set 構造器

  • Java
public class Developer {

    private String name;
    private int age;

    public Developer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;

        Developer developer = (Developer) o;

        if (age != developer.age) return false;
        return name != null ? name.equals(developer.name) : developer.name == null;

    }

    @Override
    public int hashCode() {
        int result = name != null ? name.hashCode() : 0;
        result = 31 * result + age;
        return result;
    }

    @Override
    public String toString() {
        return "Developer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}
複製程式碼
  • Kotlin
data class Developer(val name: String, val age: Int)
複製程式碼

靜態

  • Java
public class Utils {

    private Utils() { 
    }
    
    public static int getDBVersion() {
        return CURRENT_DB_VERSION;
   }
}

int db_verison = Utils.getDBVersion();
複製程式碼
  • Kotlin

Kotlin中使用object修飾靜態類,被修飾的類,可以使用類名.方法名的形式呼叫

object Utils {

    fun getDBVersion(): Int {
        return CURRENT_DB_VERSION
    }

}

var db_verison = Utils.getDBVersion()
複製程式碼

Kotlin中使用companion object修飾靜態方法,稱為伴生物件,可以使用類名.方法名的形式呼叫

class Utils {

    companion object {
        fun getDBVersion(): Int {
            return CURRENT_DB_VERSION
        }
    }
}

var db_verison = Utils.getDBVersion()
複製程式碼

許可權修飾符

Java

  • public 對所有類可見
  • default 在同一包內可見,不寫預設default
  • protected 對同一包內的類和所有子類可見
  • private 在同一類內可見

Kotlin

  • public 凡是能夠訪問到這個類的地方, 同時也能訪問這個類的public成員,不寫預設是public
  • internalmodule之內, 凡是能夠訪問到這個類的地方, 同時也能訪問到這個類的internal成員
  • protectedprivate一樣, 另外在子類中也可以訪問
  • private 表示只在這個類(以及它的所有成員)之內可以訪問,不會自動生成getter setter方法

標籤(@)

  • Java
loop:
for (int i = 0; i < 100; i++) {
    loop1:
    for (int j = 0; j < 100; j++) {
        if (i == 3) { 
            continue loop1;
        } else if(i == 5) {
            continue loop;
        } else {
            break loop1;
        }
    }
}
複製程式碼
  • Java中的標籤我們用的極少,它主要是用來控制流程語句的執行,continuebreak。用法是:在語句內部需要continuebreak的地方,在控制關鍵字後跟上你想控制的某個迴圈。簡單地說就是,一個迴圈一組標籤,起始和終止位置標籤內容一致。在迴圈內部,任意地方可以控制其他迴圈。為了方便跳轉到指定位置

  • 在迴圈開始之前用自定義的名字加上英文冒號作為起始點,然後書寫迴圈語句loop:迴圈語句體...continue/break loop;


  • Kotlin

val ints = intArrayOf(1, 2, 3, 0, 4, 5, 6)
ints.forEach foreach@ {
    if (it == 0) return@foreach
    print(it)
}
複製程式碼
  • 由於Kotlin中幾乎萬物都是表示式,所以會有方法後直接跟運算體的寫法。Kotlin中的標籤和Java中大同小異,只不過在迴圈控制上多了return,用來指定:在指定位置返回,上面的程式碼就說明在it == 0時返回,不列印,所以列印結果是123456
  • 另外Kotlin中的標籤還可以用在this關鍵字上。Java中我們通常有XXXActivity.this的寫法,用來代指XXXActivity這個引用,Kotlin中寫法是this@XXXActivity

init程式碼塊

class Test public constructor(val i: Int) {
  
    // 只對主構造方法生效
    init {
      
    }

    constructor(i: Int, s: String) : this(i) {
      
    }

    fun xxx() {

    }
}
複製程式碼

上述程式碼中,定義了Test類的兩個構造方法,引數列表不同;例項化時可以:

val test = Test(1)
val test1 = Test(1, "")
複製程式碼

而某些操作可能需要在預設/主構造方法中進行初始化,也就是單引數的構造方法中,所以這時候就有init程式碼塊;Kotlin主建構函式不能包含任何的程式碼,所以初始化的程式碼可以放到init塊中進行


##lateinit 和 by lazy

物件/變數可以通過依賴注入來初始化, 或者在單元測試的setup方法中初始化。 這種情況下,我們並不能直接在構造方法內提供一個非空構造器,但我們使用時依然想要避免物件/變數的空問題,所以。。。

  • lateinit意思是_延遲初始化_,只有當變數/物件被宣告為var時才可使用
  • by lazy意思是_懶初始化_,只有當變數/物件被宣告為val時才可使用
// by lazy 使用方式後面跟大括號,裡面進行物件/變數的例項化/賦值
// by lazy 只會在第一次使用 danluUtil / name / id 的時候才會建立物件或者例項初始化變數
// 和 java 中的懶漢式單例一樣,使用時候判空,不為空直接返回物件,為空的話例項化物件再返回
val danluUtil by lazy {
     DanluUtil(i, j)
}
val name by lazy {"名字"}
val id by lazy {1}


// lateinit 使用方式在 var 前面加上 lateinit 即可,後面跟上變數和變數型別
// lateinit 宣告的變數/物件,不能為空,也不能被立即初始化:比如下面兩種方式都是不允許的:
// lateinit var danluUtil: DanluUtil = DanluUtil(i, j)
// lateinit var danluUtil: DanluUtil?
// 大致來說,這段程式碼將變數的初始化與定義分離開了
// 使用場景包括但不限於依賴注入框架(例如 Dagger2),那些預先宣告的變數也無法成功初始化。在這種情況下,必須使用 lateinit 關鍵字確保變數在稍後將被初始化
lateinit var danluUtil: DanluUtil
// 宣告完畢後在需要用到的地方進行初始化:
danluUtil = DanluUtil(i, j)
複製程式碼

相關文章