前段时间,面试的时候,突然问到我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()。
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() { @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
🔹Javaswitch-case语法繁琐
🔹Kotlinwhen语法更简洁,when更直观,支持范围判断和表达式返回值。
9. 类默认final
Java 类默认是
open的,可以继承,除非加finalKotlin 类默认
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; } }13.kotlin的内联函数
- Kotlin 允许使用
inline关键字,将高阶函数的函数调用直接替换为函数体代码,从而减少不必要的对象创建和额外的函数调用开销。 - 主要作用:
- 避免高阶函数带来的 Lambda 表达式性能损耗。
- 允许
crossinline和noinline修饰参数,进一步控制内联行为。
inline fun execute(action: () -> Unit) { println("Before action") action() println("After action") } fun main() { execute { println("Executing task...") } }等效于:
fun main() { println("Before action") println("Executing task...") println("After action") }execute()方法的 Lambda 参数直接被展开,避免了额外的函数调用。
优点
- 减少 Lambda 运行时开销(避免创建
Function对象) - 提升代码执行效率
- 支持非局部返回(可以使用
return直接从调用函数返回)
注意事项
- 避免过度使用,内联会导致代码膨胀,影响 APK 体积和方法数量。
- 仅适用于小型 Lambda,对于大函数,内联会增加代码量而不是优化性能。
来个具体点的例子:
kotlin:
inline fun measureExecutionTime( crossinline beforeStart: () -> Unit, block: () -> Unit, crossinline afterEnd: () -> Unit ) { beforeStart() val startTime = System.currentTimeMillis() block() val endTime = System.currentTimeMillis() afterEnd() println("Execution Time: ${endTime - startTime} ms") } fun main() { measureExecutionTime( beforeStart = { println("Starting execution...") }, block = { Thread.sleep(500) // 模拟耗时操作 println("Executing task...") }, afterEnd = { println("Execution completed.") } ) }java代码:
public class Main { public static void measureExecutionTime(Runnable beforeStart, Runnable block, Runnable afterEnd) { beforeStart.run(); long startTime = System.currentTimeMillis(); block.run(); long endTime = System.currentTimeMillis(); afterEnd.run(); System.out.println("Execution Time: " + (endTime - startTime) + " ms"); } public static void main(String[] args) { measureExecutionTime( () -> System.out.println("Starting execution..."), () -> { try { Thread.sleep(500); // 模拟耗时操作 } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Executing task..."); }, () -> System.out.println("Execution completed.") ); } }Java 代码中:
Java 需要为
Runnable创建匿名内部类或 Lambda 对象,每次调用时都需要分配额外的内存。
Runnable作为参数传递,执行block.run(),涉及额外的函数调用。Java 的 Lambda 不能访问
return语句,只能使用return结束Runnable的逻辑。Kotlin 内联:
inline使得measureExecutionTime不会创建任何 Lambda 对象,它的调用会被直接替换为代码块,消除对象分配和函数调用的开销。直接展开代码,避免额外的函数调用。
支持非局部返回(普通 Lambda 不能直接
return退出measureExecutionTime,但inline可以)。
14. Any vs Object
在 Kotlin 中,Any是所有非null类型的超类,而在 Java 中,Object是所有类的超类。但它们并不完全等价,主要区别如下:
1.Any不包含null,而Object可以
在 Kotlin 中,
Any不能存储null,如果需要允许null,必须使用Any?。Java 的
Object默认可以存储null。
2.Any只有equals、hashCode、toString
Kotlin 的
Any只包含equals()、hashCode()和toString(),没有wait()、notify()这些Object的方法。Java 的
Object还提供了wait()、notify()、clone()等线程相关的方法。
3.Any不能直接用于 Java 互操作
在 Java 方法中,如果你需要一个Object,KotlinAny不能直接替代它,必须显式转换为Object。
5.Any是Unit和Nothing的超类,而Object不是
在 Kotlin,Unit(等价于 Javavoid)和Nothing也是Any的子类
15.智能类型转换(Smart Casts)
概念
- Kotlin 编译器可以自动推断类型,避免手动类型转换 (
cast),提升代码可读性和安全性。 - 只要 Kotlin 确定变量不会改变类型,就可以自动转换。
java代码:
void printLength(Object obj) { if (obj instanceof String) { String str = (String) obj; // 需要手动转换 System.out.println(str.length()); } }kotlin代码:
fun printLength(obj: Any) { if (obj is String) { // 这里 obj 自动转换为 String println(obj.length) // 直接使用,不需要手动转换 } }强制转换(as和as?),其中as?安全转换,避免ClassCastException
val obj: Any = 123 val str: String? = obj as? String // 转换失败返回 null println(str) // nullJava开发的就业市场正在经历结构性调整,竞争日益激烈
传统纯业务开发岗位(如仅完成增删改查业务的后端工程师)的需求,特别是入门级岗位,正显著萎缩。随着企业技术需求升级,市场对Java人才的要求已从通用技能转向了更深入的领域经验(如云原生、微服务)或前沿的AI集成能力。这也导致岗位竞争加剧,在一、二线城市,求职者不仅面临技术内卷,还需应对学历与项目经验的高门槛。
大模型为核心的AI领域正展现出前所未有的就业热度与人才红利
2025年,AI相关新发岗位数量同比激增543%,单月增幅最高超过11倍,大模型算法工程师位居热门岗位前列。行业顶尖人才的供需严重失衡,议价能力极强,跳槽薪资涨幅可达30%-50%。值得注意的是,市场并非单纯青睐算法研究员,而是急需能将大模型能力落地于复杂业务系统的工程人才。这使得具备企业级架构思维和复杂系统整合经验的Java工程师,在向“Java+大模型”复合人才转型时拥有独特优势,成为企业竞相争夺的对象,其薪资天花板也远高于传统Java岗位。
说真的,这两年看着身边一个个搞Java、C++、前端、数据、架构的开始卷大模型,挺唏嘘的。大家最开始都是写接口、搞Spring Boot、连数据库、配Redis,稳稳当当过日子。
结果GPT、DeepSeek火了之后,整条线上的人都开始有点慌了,大家都在想:“我是不是要学大模型,不然这饭碗还能保多久?”
先给出最直接的答案:一定要把现有的技术和大模型结合起来,而不是抛弃你们现有技术!掌握AI能力的Java工程师比纯Java岗要吃香的多。
即使现在裁员、降薪、团队解散的比比皆是……但后续的趋势一定是AI应用落地!大模型方向才是实现职业升级、提升薪资待遇的绝佳机遇!
如何学习AGI大模型?
作为一名热心肠的互联网老兵,我决定把宝贵的AI知识分享给大家。 至于能学习到多少就看你的学习毅力和能力了 。我已将重要的AI大模型资料包括AI大模型入门学习思维导图、精品AI大模型学习书籍手册、视频教程、实战学习等录播视频免费分享出来。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享**
一、2025最新大模型学习路线
一个明确的学习路线可以帮助新人了解从哪里开始,按照什么顺序学习,以及需要掌握哪些知识点。大模型领域涉及的知识点非常广泛,没有明确的学习路线可能会导致新人感到迷茫,不知道应该专注于哪些内容。
我们把学习路线分成L1到L4四个阶段,一步步带你从入门到进阶,从理论到实战。
L1级别:AI大模型时代的华丽登场
L1阶段:我们会去了解大模型的基础知识,以及大模型在各个行业的应用和分析;学习理解大模型的核心原理,关键技术,以及大模型应用场景;通过理论原理结合多个项目实战,从提示工程基础到提示工程进阶,掌握Prompt提示工程。
L2级别:AI大模型RAG应用开发工程
L2阶段是我们的AI大模型RAG应用开发工程,我们会去学习RAG检索增强生成:包括Naive RAG、Advanced-RAG以及RAG性能评估,还有GraphRAG在内的多个RAG热门项目的分析。
L3级别:大模型Agent应用架构进阶实践
L3阶段:大模型Agent应用架构进阶实现,我们会去学习LangChain、 LIamaIndex框架,也会学习到AutoGPT、 MetaGPT等多Agent系统,打造我们自己的Agent智能体;同时还可以学习到包括Coze、Dify在内的可视化工具的使用。
L4级别:大模型微调与私有化部署
L4阶段:大模型的微调和私有化部署,我们会更加深入的探讨Transformer架构,学习大模型的微调技术,利用DeepSpeed、Lamam Factory等工具快速进行模型微调;并通过Ollama、vLLM等推理部署框架,实现模型的快速部署。
整个大模型学习路线L1主要是对大模型的理论基础、生态以及提示词他的一个学习掌握;而L3 L4更多的是通过项目实战来掌握大模型的应用开发,针对以上大模型的学习路线我们也整理了对应的学习视频教程,和配套的学习资料。
二、大模型经典PDF书籍
书籍和学习文档资料是学习大模型过程中必不可少的,我们精选了一系列深入探讨大模型技术的书籍和学习文档,它们由领域内的顶尖专家撰写,内容全面、深入、详尽,为你学习大模型提供坚实的理论基础。(书籍含电子版PDF)
三、大模型视频教程
对于很多自学或者没有基础的同学来说,书籍这些纯文字类的学习教材会觉得比较晦涩难以理解,因此,我们提供了丰富的大模型视频教程,以动态、形象的方式展示技术概念,帮助你更快、更轻松地掌握核心知识。
四、大模型项目实战
学以致用,当你的理论知识积累到一定程度,就需要通过项目实战,在实际操作中检验和巩固你所学到的知识,同时为你找工作和职业发展打下坚实的基础。
五、大模型面试题
面试不仅是技术的较量,更需要充分的准备。
在你已经掌握了大模型技术之后,就需要开始准备面试,我们将提供精心整理的大模型面试题库,涵盖当前面试中可能遇到的各种技术问题,让你在面试中游刃有余。
因篇幅有限,仅展示部分资料,需要点击下方链接即可前往获取
2025最新版CSDN大礼包:《AGI大模型学习资源包》免费分享