Kotlin和Java区别

哈哈哈,前段时间,面试的时候,突然问到我Kotlin和Java的区别,一下子把我问懵逼了,确实没遇到问这个的,想了下,说了下Kotlin的编译时空检查机制,代码更简洁,很多封装好的API可以直接调用,Kotlin有Jetpack全家桶,有协程,有lateinit和by lazy懒加载机制等等,后面着重问我协程去了,但是我知道我也有很多没有答上。

今天自己做个总结:

1. 语法简洁性

🔹 Kotlin 代码通常比 Java 更简洁,减少了模板代码(boilerplate)。

🔸 Java 示例(获取 List 的大小并遍历):

java 复制代码
List<String> list = Arrays.asList("A", "B", "C");
for (String item : list) {
    System.out.println(item);
}

Kotlin

Kotlin 复制代码
val list = listOf("A", "B", "C")
list.forEach { println(it) }

2. Null 安全

🔹 Java 中 NullPointerException (NPE) 是常见错误

java 复制代码
String name = null; 
System.out.println(name.length()); // 运行时崩溃:NullPointerException

🔹 Kotlin 通过可空类型和安全调用避免 NPE:

Kotlin 复制代码
var name: String? = null
println(name?.length) // 安全调用,避免 NPE
  • ? 允许 null
  • ?. 安全访问,避免 NPE
  • !! 强制非空,可能引发异常,尽量少用。

3. 数据类 (Data Class)

🔹 Java 需要大量代码来定义 POJO(数据类):

Kotlin 复制代码
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 只需一行代码:

Kotlin 复制代码
data class User(val name: String, val age: Int)
  • 自动生成 getter/settertoString()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 需要创建工具类来扩展已有类的功能

Kotlin 复制代码
public class StringUtils {
    public static String capitalize(String str) {
        return str.substring(0, 1).toUpperCase() + str.substring(1);
    }
}
String result = StringUtils.capitalize("hello");

🔹 Kotlin 直接扩展类的方法

Kotlin 复制代码
fun String.capitalizeFirst(): String = this.replaceFirstChar { it.uppercaseChar() }
val result = "hello".capitalizeFirst()

5. 函数式编程

Kotlin 支持 高阶函数Lambda 表达式,让代码更优雅。

🔹 Java 的匿名内部类:

java 复制代码
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        System.out.println("Clicked");
    }
});

🔹 Kotlin 的 Lambda 表达式:

Kotlin 复制代码
button.setOnClickListener { println("Clicked") }

6. 协程 vs. Java 线程

🔹 Java 使用线程管理并发,代码较复杂:

Kotlin 复制代码
new Thread(new Runnable() {
    @Override
    public void run() {
        System.out.println("线程运行中...");
    }
}).start();

🔹 Kotlin 协程更高效,且不会阻塞线程

Kotlin 复制代码
GlobalScope.launch {
    println("协程运行中...")
}
  • 协程比 Java 线程更轻量,可以高效处理并发任务。管理起来也很轻松,可以和生命周期绑定

Kotlin 协程(一)协程的定义及基础使用_kotlin 协程使用-CSDN博客

7. Smart Cast(智能类型转换)

🔹 Java 需要显式类型转换

java 复制代码
Object obj = "Hello";
if (obj instanceof String) {
    String str = (String) obj; // 需要手动转换
}

🔹 Kotlin 自动类型转换

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)主要有两种方式:

  1. lazy适用于 val 只读变量
  2. lateinit适用于 var 可变变量

Kotlin by lazy和lateinit的使用及区别_kotlin by lazy 与lateinit-CSDN博客

12.单例模式

传统的懒汉式(lazy + @Volatile + synchronized)

Kotlin 复制代码
class Singleton private constructor() {
    companion object {
        @Volatile
        private var instance: Singleton? = null

        fun getInstance(): Singleton {
            return instance ?: synchronized(this) {//第一次空检查
                instance ?: Singleton().also { instance = it }//第二次空检查
            }
        }
    }
}

这里的双重检查:

  1. 第一次检查 (instance ?:)

    • 避免不必要的同步开销。
    • 如果已经初始化 ,直接返回,避免进入 synchronized 代码块,提高性能。
  2. 同步代码块内部的第二次检查 (instance ?:)

    • 由于多个线程可能同时通过第一次检查进入 synchronized,所以 需要再次检查 instance 是否为 null,防止重复创建实例。

为什么要用 @Volatile

  • @Volatile 防止指令重排序(保证可见性)。

  • 如果不加 @Volatile,可能会发生 部分初始化(对象创建未完成,别的线程就拿到不完整的实例)。

  • 避免可能的 NullPointerException(NPE)。

lazy懒加载

Kotlin 复制代码
class Singleton private constructor() {
    companion object {
        val instance: Singleton by lazy { Singleton() }
    }
}
  • 线程安全(lazy 默认是 LazyThreadSafetyMode.SYNCHRONIZED)。
  • 更简洁 ,不需要 synchronized@Volatile

最简单的单例

Kotlin 复制代码
object Singleton {
    fun doSomething() {
        println("Hello from Singleton!")
    }
}
  • 线程安全, 在 Kotlin 中,object 关键字天然是线程安全的 ,因为它的初始化由 JVM 类加载机制(Class Loading Mechanism) 保证,由于 JVM 类加载过程是线程安全的 ,所以 object 也是线程安全的!

  • 写法简单

  • 类加载时就初始化(饿汉式)

🔹 双重检查锁的 Java 代码

Kotlin 复制代码
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;
    }
}
相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说12 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json