以下是一份 超详细的 Java 与 Kotlin 对比学习指南,涵盖语法、设计理念和实际场景的深度对比,帮助您从 Java 平滑过渡到 Kotlin。
一、基础语法对比
1. 程序入口
Java
java
public class Main {
public static void main(String[] args) {
System.out.println("Hello, Java!");
}
}
- 必须定义
public static void main
方法。 - 类名必须与文件名一致。
Kotlin
kotlin
fun main() {
println("Hello, Kotlin!")
}
// 或带参数
fun main(args: Array<String>) {
println(args.joinToString())
}
- 无需类包装,直接定义
main
函数。 println
是 Kotlin 标准库函数,无需System.out
。
2. 变量声明
Java
java
final String name = "Java"; // 不可变
int age = 25; // 可变
Integer nullableAge = null; // 可空包装类型
- 使用
final
声明常量。 - 基本类型(
int
)不能为null
,需用包装类型(Integer
)。
Kotlin
kotlin
val name = "Kotlin" // 不可变(类型推断为 String)
var age = 25 // 可变
var nullableAge: Int? = null // 可空类型(显式声明)
val
类似final
,var
可变。- 类型后加
?
表示可空,编译时强制检查。
3. 函数定义
Java
java
public int sum(int a, int b) {
return a + b;
}
// 重载
public int sum(int a, int b, int c) {
return a + b + c;
}
- 必须指定返回类型和访问修饰符(如
public
)。 - 重载需手动编写多个方法。
Kotlin
kotlin
fun sum(a: Int, b: Int) = a + b // 单行表达式
fun sum(a: Int, b: Int, c: Int = 0) = a + b + c // 默认参数
- 支持表达式函数(省略
{}
和return
)。 - 默认参数减少重载需求。
二、面向对象对比
1. 类与构造函数
Java
java
public class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
// getter/setter 省略...
}
- 字段通常私有,需手动生成构造方法和 getter/setter。
Kotlin
kotlin
class Person(val name: String, var age: Int) // 主构造函数
val
生成只读属性(只有 getter),var
生成可变属性(getter/setter)。- 主构造函数直接声明属性。
2. 继承与接口
Java
java
public class Animal {
public void eat() { ... }
}
public class Dog extends Animal {
@Override
public void eat() { ... }
}
- 使用
extends
和implements
关键字。 - 默认类可继承(除非用
final
修饰)。
Kotlin
kotlin
open class Animal { // 必须用 open 允许继承
open fun eat() { ... } // 允许重写的方法需 open
}
class Dog : Animal() {
override fun eat() { ... }
}
- 类和方法默认
final
,需显式标记open
才能继承/重写。 - 使用
:
替代extends
/implements
。
3. 数据类
Java
java
public class User {
private int id;
private String name;
// 需手动实现 equals(), hashCode(), toString()
// 或使用 Lombok @Data
}
- 需手动编写或依赖 Lombok。
Kotlin
kotlin
data class User(val id: Int, val name: String)
- 自动生成
equals()
、hashCode()
、toString()
、copy()
等。
三、空安全机制对比
1. 可空性处理
Java
java
String str = null; // 允许
int length = str.length(); // 运行时 NullPointerException
- 无编译时检查,依赖注解(如
@Nullable
)或手动判空。
Kotlin
kotlin
var str: String? = null // 必须显式声明可空
val length = str?.length // 安全调用(返回 Int?)
val nonNullLength = str!!.length // 非空断言(可能抛 NPE)
val safeLength = str?.length ?: 0 // Elvis 操作符
- 编译时强制检查可空性,减少运行时
NullPointerException
。
四、集合操作对比
1. 集合创建
Java
java
List<String> list = Arrays.asList("a", "b", "c");
list.add("d"); // 抛出 UnsupportedOperationException(不可变)
List<String> mutableList = new ArrayList<>(list);
Kotlin
kotlin
val list = listOf("a", "b", "c") // 不可变
val mutableList = mutableListOf("a", "b") // 可变
2. 集合操作
Java
java
List<Integer> numbers = Arrays.asList(1, 2, 3);
List<Integer> evens = numbers.stream()
.filter(n -> n % 2 == 0)
.collect(Collectors.toList());
Kotlin
kotlin
val numbers = listOf(1, 2, 3)
val evens = numbers.filter { it % 2 == 0 } // 更简洁
五、函数式编程对比
1. Lambda 表达式
Java
java
Runnable task = () -> System.out.println("Running");
Collections.sort(list, (a, b) -> a.compareTo(b));
Kotlin
kotlin
val task = { println("Running") }
list.sortedBy { it } // 更自然的语法
2. 高阶函数
Java
java
public interface Operation {
int execute(int a, int b);
}
public int calculate(int a, int b, Operation op) {
return op.execute(a, b);
}
// 调用
calculate(2, 3, (a, b) -> a + b);
Kotlin
kotlin
fun calculate(a: Int, b: Int, op: (Int, Int) -> Int) = op(a, b)
// 调用
calculate(2, 3) { x, y -> x + y }
六、并发编程对比
1. 线程 vs 协程
Java
java
new Thread(() -> {
try {
Thread.sleep(1000);
System.out.println("Done");
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
Kotlin
kotlin
GlobalScope.launch {
delay(1000L) // 挂起函数,不阻塞线程
println("Done")
}
七、扩展机制对比
1. 扩展函数
Java
无法直接扩展类,需通过工具类:
java
public class StringUtils {
public static String reverse(String s) {
return new StringBuilder(s).reverse().toString();
}
}
String reversed = StringUtils.reverse("hello");
Kotlin
kotlin
fun String.reverse() = this.reversed()
val reversed = "hello".reverse()
八、与 Java 互操作
1. 调用 Java 代码
Kotlin 可直接使用 Java 类和库:
kotlin
val javaList = ArrayList<String>() // Java 的 ArrayList
javaList.add("Kotlin")
2. Java 调用 Kotlin
-
Kotlin 的
顶级函数
在 Java 中通过生成的类调用:java// Kotlin 文件:Utils.kt fun log(message: String) { ... } // Java 调用 UtilsKt.log("Hello");
-
伴生对象:
java// Kotlin class MyClass { companion object { fun create() = MyClass() } } // Java 调用 MyClass.Companion.create();
九、关键总结
特性 | Java | Kotlin |
---|---|---|
变量声明 | final + 类型显式 |
val /var + 类型推断 |
空安全 | 需手动检查或注解 | 编译时强制检查(? 和 !! ) |
函数式编程 | Stream API(Java 8+) | 原生支持(Lambda、扩展函数) |
数据类 | 手动编写或 Lombok | data class 自动生成 |
并发 | 线程/ExecutorService | 协程(轻量级线程) |
扩展机制 | 静态工具类 | 扩展函数/属性 |
与 Java 互操作 | 天然兼容 | 100% 兼容,但需注意空安全注解 |
十、迁移建议
- 从工具类开始:将 Java 工具类逐步改为 Kotlin 扩展函数。
- 优先迁移数据类 :用
data class
替代 Java Bean。 - 逐步引入空安全 :在混合代码中使用
@Nullable
/@NotNull
注解。 - 尝试协程:替换简单的异步任务(如网络请求)。
通过对比学习,可以更深入理解 Kotlin 的设计哲学,写出更简洁、安全的代码!