哈哈哈,前段时间,面试的时候,突然问到我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; }
@Override
public String toString() { return "User{name='" + name + "', age=" + age + "}"; }
}
🔹 Kotlin 只需一行代码:
data class User(val name: String, val age: Int)
- 自动生成
getter/setter
、toString()
、equals()
和hashCode()
。
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() {
@Override
public void onClick(View v) {
System.out.println("Clicked");
}
});
🔹 Kotlin 的 Lambda 表达式:
button.setOnClickListener { println("Clicked") }
6. 协程 vs. Java 线程
🔹 Java 使用线程管理并发,代码较复杂:
new Thread(new Runnable() {
@Override
public 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 {
@Volatile
private var instance: Singleton? = null
fun 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;
}
}