哈哈哈,前段時間,面試的時候,突然問到我Kotlin和Java的區別,一下子把我問懵逼了,確實沒遇到問這個的,想了下,說了下Kotlin的編譯時空檢查機制,代碼更簡潔,很多封裝好的API可以直接調用,Kotlin有Jetpack全家桶,有協程,有lateinit和by lazy懶加載機制等等,后面著重問我協程去了,但是我知道我也有很多沒有答上。
今天自己做個總結:
1. 語法簡潔性
🔹 Kotlin 代碼通常比 Java 更簡潔,減少了模板代碼(boilerplate)。
🔸 Java 示例(獲取 List 的大小并遍歷):
List<String> list = Arrays.asList("A", "B", "C");
for (String item : list) {System.out.println(item);
}
Kotlin
val list = listOf("A", "B", "C")
list.forEach { println(it) }
2. Null 安全
🔹 Java 中 NullPointerException
(NPE) 是常見錯誤:
String name = null;
System.out.println(name.length()); // 運行時崩潰:NullPointerException
🔹 Kotlin 通過可空類型和安全調用避免 NPE:
var name: String? = null
println(name?.length) // 安全調用,避免 NPE
?
允許null
值?.
安全訪問,避免 NPE!!
強制非空,可能引發異常,盡量少用。
3. 數據類 (Data Class)
🔹 Java 需要大量代碼來定義 POJO(數據類):
public class User {private String name;private int age;public User(String name, int age) { this.name = name; this.age = age; }public String getName() { return name; }public int getAge() { return age; }public void setName(String name) { this.name = name; }public void setAge(int age) { this.age = age; }@Overridepublic String toString() { return "User{name='" + name + "', age=" + age + "}"; }
}
🔹 Kotlin 只需一行代碼:
data class User(val name: String, val age: Int)
- 自動生成
getter/setter
、toString()
、equals()
和hashCode()
。
data class的詳細介紹和區別:Serializable,Parcelable和data class的區別_data class parcelable-CSDN博客文章瀏覽閱讀992次,點贊24次,收藏26次。序列化是將對象的狀態(屬性數據)轉換為字節流或其他可存儲或傳輸的格式的過程。主要作用存儲:將對象保存到文件或數據庫中。傳輸:在網絡中傳輸對象,比如在客戶端與服務器之間傳遞數據。緩存:將對象轉化為可恢復的格式,便于后續恢復使用。序列化后7. 什么是反序列化(Deserialization)?反序列化是將序列化后的字節流(或存儲格式)重新轉換回原始對象的過程。主要作用從存儲或傳輸的格式中重建對象。恢復數據到應用中,便于程序繼續使用。8.序列化與反序列化的用途網絡傳輸。_data class parcelablehttps://blog.csdn.net/LoveFHM/article/details/143875848?spm=1001.2014.3001.5502
4. 擴展函數 (Extension Functions)
🔹 Java 需要創建工具類來擴展已有類的功能
public class StringUtils {public static String capitalize(String str) {return str.substring(0, 1).toUpperCase() + str.substring(1);}
}
String result = StringUtils.capitalize("hello");
🔹 Kotlin 直接擴展類的方法
fun String.capitalizeFirst(): String = this.replaceFirstChar { it.uppercaseChar() }
val result = "hello".capitalizeFirst()
5. 函數式編程
Kotlin 支持 高階函數 和 Lambda 表達式,讓代碼更優雅。
🔹 Java 的匿名內部類:
button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {System.out.println("Clicked");}
});
🔹 Kotlin 的 Lambda 表達式:
button.setOnClickListener { println("Clicked") }
6. 協程 vs. Java 線程
🔹 Java 使用線程管理并發,代碼較復雜:
new Thread(new Runnable() {@Overridepublic void run() {System.out.println("線程運行中...");}
}).start();
🔹 Kotlin 協程更高效,且不會阻塞線程
GlobalScope.launch {println("協程運行中...")
}
- 協程比 Java 線程更輕量,可以高效處理并發任務。管理起來也很輕松,可以和生命周期綁定
Kotlin 協程(一)協程的定義及基礎使用_kotlin 協程使用-CSDN博客
7. Smart Cast(智能類型轉換)
🔹 Java 需要顯式類型轉換
Object obj = "Hello";
if (obj instanceof String) {String str = (String) obj; // 需要手動轉換
}
🔹 Kotlin 自動類型轉換
val obj: Any = "Hello"
if (obj is String) {println(obj.length) // Kotlin 自動轉換,無需 `(String) obj`
}
-
智能類型推斷:Kotlin 可以自動推斷變量類型,無需顯式聲明,如
val name = "Lee"
而不需要String name = "Lee";
。
?
8. when
取代 switch
🔹 Java switch-case
語法繁瑣
🔹 Kotlin when
語法更簡潔,when
更直觀,支持范圍判斷和表達式返回值。
9. 類默認 final
-
Java 類默認是
open
的,可以繼承,除非加final
-
Kotlin 類默認
final
,必須顯式open
允許繼承
10.總結對比表
特性 | Java | Kotlin |
---|---|---|
語法 | 冗長 | 簡潔 |
Null 安全 | 可能導致 NPE | 避免 NPE |
數據類 | 需要手寫 getter/setter | data class 自動生成 |
擴展函數 | 需要工具類 | 直接擴展 |
高階函數 | 需要匿名類 | 直接支持 Lambda |
并發 | 線程(較重) | 協程(輕量) |
類型轉換 | 需手動轉換 | 自動 Smart Cast |
switch 語法 | switch-case | when |
類默認行為 | 默認可繼承 | 默認 final |
其他的:
11. Kotlin的懶加載
在 Kotlin 中,懶加載(Lazy Initialization)主要有兩種方式:
lazy
(適用于 val 只讀變量)lateinit
(適用于 var 可變變量)
Kotlin by lazy和lateinit的使用及區別_kotlin by lazy 與lateinit-CSDN博客
12.單例模式
傳統的懶漢式(lazy + @Volatile + synchronized)
class Singleton private constructor() {companion object {@Volatileprivate var instance: Singleton? = nullfun getInstance(): Singleton {return instance ?: synchronized(this) {//第一次空檢查instance ?: Singleton().also { instance = it }//第二次空檢查}}}
}
這里的雙重檢查:
-
第一次檢查 (
instance ?:
)- 避免不必要的同步開銷。
- 如果已經初始化,直接返回,避免進入
synchronized
代碼塊,提高性能。
-
同步代碼塊內部的第二次檢查 (
instance ?:
)- 由于多個線程可能同時通過第一次檢查進入
synchronized
,所以 需要再次檢查instance
是否為null
,防止重復創建實例。
- 由于多個線程可能同時通過第一次檢查進入
為什么要用 @Volatile
?
-
@Volatile
防止指令重排序(保證可見性)。 -
如果不加
@Volatile
,可能會發生 部分初始化(對象創建未完成,別的線程就拿到不完整的實例)。 -
避免可能的 NullPointerException(NPE)。
lazy懶加載
class Singleton private constructor() {companion object {val instance: Singleton by lazy { Singleton() }}
}
- 線程安全(
lazy
默認是LazyThreadSafetyMode.SYNCHRONIZED
)。 - 更簡潔,不需要
synchronized
和@Volatile
。
最簡單的單例
object Singleton {fun doSomething() {println("Hello from Singleton!")}
}
-
線程安全,在 Kotlin 中,
object
關鍵字天然是線程安全的,因為它的初始化由 JVM 類加載機制(Class Loading Mechanism) 保證,由于 JVM 類加載過程是線程安全的,所以object
也是線程安全的! -
寫法簡單
-
類加載時就初始化(餓漢式)
🔹 雙重檢查鎖的 Java 代碼
public class Singleton {private static volatile Singleton instance;private Singleton() {}public static Singleton getInstance() {if (instance == null) { // 第一次檢查(避免不必要的同步)synchronized (Singleton.class) { // 線程同步if (instance == null) { // 第二次檢查(確保只創建一次)instance = new Singleton();}}}return instance;}
}
?