2026/1/9 22:42:16
网站建设
项目流程
专业做尼泊尔的旅行网站,老薛主机wordpress模板,南通公司网站建设,返利网 网站开发Java基础——接口接口概念 官方解释#xff1a;Java接口是一系列方法的声明#xff0c;是一些方法特征的集合#xff0c;**一个接口只有方法的特征没有方法的实现#xff0c;因此这些方法可以在不同的地方被不同的类实现#xff0c;而这些实现可以具有不同的行为#xff…Java基础——接口接口概念官方解释Java接口是一系列方法的声明是一些方法特征的集合**一个接口只有方法的特征没有方法的实现因此这些方法可以在不同的地方被不同的类实现而这些实现可以具有不同的行为功能**。 我的解释接口可以理解为一种特殊的类里面全部是由**全局常量**和**公共的抽象方法**所组成。接口是解决**Java无法使用多继承**的一种手段但是接口在实际中更多的作用是**制定标准**的。或者我们可以直接把接口理解为**100%的抽象类**既接口中的方法**必须全部**是抽象方法。JDK1.8之前可以这样理解接口的特点就像一个类一样一个接口也能够拥有方法和属性但是在接口中声明的方法默认是抽象的。**即只有方法标识符而没有方法体**。接口指明了一个类必须要做什么和不能做什么相当于类的蓝图。一个接口就是描述一种能力比如“运动员”也可以作为一个接口并且任何实现“运动员”接口的类都必须有能力实现奔跑这个动作或者implement move()方法所以接口的作用就是告诉类你要实现我这种接口代表的功能你就必须实现某些方法我才能承认你确实拥有该接口代表的某种能力。如果一个类实现了一个接口中要求的所有的方法然而没有提供方法体而仅仅只有方法标识那么这个类一定是一个抽象类。必须记住抽象方法只能存在于抽象类或者接口中但抽象类中却能存在非抽象方法即有方法体的方法。接口是百分之百的抽象类一个JAVA库中接口的例子是Comparator 接口这个接口代表了“能够进行比较”这种能力任何类只要实现了这个Comparator接口的话这个类也具备了“比较”这种能力那么就可以用来进行排序操作了。为什么要用接口接口被用来描述一种抽象。因为Java不像C一样支持多继承所以Java可以通过实现接口来弥补这个局限。接口也被用来实现解耦。接口被用来实现抽象而抽象类也被用来实现抽象为什么一定要用接口呢接口和抽象类之间又有什么区别呢原因是抽象类内部可能包含非final的变量但是在接口中存在的变量一定是finalpublic,static的。接口的语法实现为了声明一个接口我们使用**interface**这个关键字在接口中的所有方法都必须只声明方法标识而不要去声明具体的方法体因为具体的方法体的实现是由继承该接口的类来去实现的因此接口并不用管具体的实现。接口中的属性默认为Public Static Final.一个类实现这个接口必须实现这个接口中定义的所有的抽象方法。 一个简单的接口就像这样拥有全局变量和抽象方法。为了实现这个接口我们使用implements关键词去实现接口其中testClass类实现了我们上面刚才定义的 in1 这个接口既然你要实现接口也就是实现接口代表的一种能力那么你就必须去实现接口给你规定的方法只有把接口给你规定的抽象方法都给实现了才承认你这个类实现了这个接口实现了这个接口代表的某种功能。上图实现了接口中规定的display方法。写一个测试类用来测试一下我们刚才实现的这个接口因为testclass类的对象t实现了接口规定的display方法那么自然而然就可以调用display方法咯。有兴趣的同学可以去这个在线IDE亲自试一试[点击打开链接](https://ide.geeksforgeeks.org/9MpGUQC5uc 点击打开链接)接口的进一步理解我们知道如果某个设备需要向电脑中读取或者写入某些东西这些设备一般都是采用USB方式与电脑连接的我们发现只要带有USB功能的设备就可以插入电脑中使用了那么我们可以认为USB就是一种功能这种功能能够做出很多的事情实现很多的方法其实USB就可以看做是一种标准一种接口只要实现了USB标准的设备我就认为你已经拥有了USB这种功能。因为你实现了我USB标准中规定的方法下面是具体的例子先声明USB接口其中规定了要实现USB接口就必须实现接口规定实现的read( )和write( )这两个方法。interfaceUSB {voidread();voidwrite();}然后在写一个U盘类和一个键盘类这两个类都去实现USB接口。实现其中的方法classYouPanimplementsUSB {Overridepublic voidread() {System.out.println(“U****盘正在通过USB功能读取数据”);}Overridepublic voidwrite() {System.out.println(“U****盘正在通过USB功能写入数据”);}}这是U盘的具体实现。classJianPanimplementsUSB {Overridepublic voidread() {System.out.println(“****键盘正在通过USB功能读取数据”);}Overridepublic voidwrite() {System.out.println(“****键盘正在通过USB功能写入数据”);}}这是键盘的具体实现。那么现在U盘和键盘都实现了USB功能也就是说U盘和键盘都能够调用USB接口中规定的方法并且他们实现的方式都不一样。我们在写一个测试来看看具体的实现public classMain {public static voidmain(String[] args) {_//_生成一个实现可USB接口标准的U盘对象YouPan youPan newYouPan();_//_调用U盘的read( )方法读取数据youPan.read();_//_调用U盘的write( )方法写入数据youPan.write();_//_生成一个实现可USB接口标准的键盘对象JianPan jianPan newJianPan();_//_调用键盘的read( )方法读取数据jianPan.read();_//_调用键盘的write( )方法写入数据jianPan.write();}}结果如下感兴趣的同学可以去在线IDE平台自己验证一下[点击打开链接](https://ide.geeksforgeeks.org/ONQ6pbZ4mP 点击打开链接)关于接口的几个重点我们不能直接去实例化一个接口因为接口中的方法都是抽象的是没有方法体的这样怎么可能产生具体的实例呢但是我们可以使用接口类型的引用指向一个实现了该接口的对象并且可以调用这个接口中的方法。因此上图中最后的方法调用我们还可以这样写实际上就是使用了Java中多态的特性public classMain {public static voidmain(String[] args) {_//_生成一个实现可USB接口标准的U盘对象//但是使用一个接口引用指向对象//USB接口类引用可以指向一个实现了USB接口的对象USB youPan newYouPan();_//_调用U盘的read( )方法读取数据youPan.read();_//_调用U盘的write( )方法写入数据youPan.write();_//_生成一个实现可USB接口标准的键盘对象//但是使用一个接口引用指向对象//USB接口类引用可以指向一个实现了USB接口的对象USB jianPan newJianPan();_//_调用键盘的read( )方法读取数据jianPan.read();_//_调用键盘的write( )方法写入数据jianPan.write();}}2.一个类可以实现不止一个接口。3.一个接口可以继承于另一个接口或者另一些接口接口也可以继承并且可以多继承。4.一个类如果要实现某个接口的话那么它必须要实现这个接口中的所有方法。5.接口中所有的方法都是抽象的和public的所有的属性都是public,static,final的。6.接口用来弥补类无法实现多继承的局限。7.接口也可以用来实现解耦。接口的通俗理解前面我们讲多态的时候用“空调”——“遥控器”的方式去理解多态实际上在上面的的几个重点中的第一条讲的也是多态的实现比如我们可以把“节能”作为一种标准或者说节能就是一个“接口”这个接口中有一个方法叫做变频方法任何空调如果要称得上叫做节能空调的话那么必须实现“节能”这个接口实现“节能”这个接口也就必须实现“节能”接口中规定实现的“变频”方法这样才算是真正的实现了“节能”这个接口实现了“节能”这个功能。 当某个空调实现了“节能”接口后这个空调就具备了节能的功能那么我们也可以不用空调类的引用指向空调对象我们可以直接使用一个“节能”接口类型引用的“遥控器”去指向“空调”虽然这个“遥控器”上面只有一个按键只有一个“变频”的方法但是“遥控器”所指向的空调是实现了“节能”这个接口的是有“变频”方法的实现的我们用这个只有一个“变频”方法的遥控器去命令空调调用“变频”方法也是行得通的实在不清楚的同学可以去看我的另一篇文章[JAVA之对象的多态性](https://blog.csdn.net/qq_19782019/article/details/79788326 JAVA之对象的多态性)。接口的标识用法虽然接口内部定义了一些抽象方法**但是并不是所有的接口内部都必须要有方法**比如Seriallizable接口Seriallizable接口的作用是使对象能够“序列化”但是Seriallizable接口中却没有任何内容也就是说如果有一个类需要实现“序列化”的功能则这个类必须去实现Seriallizable接口但是却并不用实现方法因为接口中没有方法此时这个Serilizable接口就仅仅是一个“标识”接口是用来标志一个类的标志这个类具有这个“序列化”功能。具体的实现请参考我的另一篇文章——JAVA之IO流。接口在生活中的思想体现其实在我们的生活当中有很多地方都体现了“接口”的思想想必正在阅读这篇博文的你是不是也喜欢摄影呢玩摄影的童鞋都知道单反由相机和镜头组成相机分不同的型号有半画幅的也有全画幅的。镜头也是一样的分长焦短焦还有定焦和变焦。每种镜头都有各自特定的发挥场景。正是因为镜头的多元化使得我们的摄影能够“术业有专攻”。大家想一想如果我们的单反相机部分和镜头部分是固定在一起的不能够更换镜头那么将会多么的糟糕啊因此每个相机品牌为了能够兼容不同的镜头各自发布了一套镜头卡口的标准这套标准就好比我们前面提到的“接口”都是某种“约束”。举个栗子我们佳能的相机不管你是哪一家镜头生产厂商腾龙也好适马也好只要你按照我佳能卡口的标准来生产镜头你生产的镜头都能够很好的在我佳能相机上面驱动。佳能EF卡口镜头是佳能公司为其单反相机和电影摄影机设计的一系列镜头。除了佳能原厂生产的EF镜头外还有一些第三方镜头制造商生产的镜头也可以适配佳能EF卡口。以下是一些可以适配佳能EF卡口的镜头品牌 1. 腾龙Tamron腾龙提供了多款兼容佳能EF卡口的镜头如腾龙EF 18-400这是一款覆盖超广角到超远摄的变焦镜头。 2. 适马Sigma适马也生产了一系列兼容佳能EF卡口的镜头包括适马EF 20mm F1.8 EX DG和适马ART系列镜头如35mm F1.4和85mm F1.4。 3. 永诺Yongnuo永诺提供了价格相对便宜的EF卡口镜头选项例如永诺EF 50mm F1.4 EX和EF 100 F2.0。 4. 佳能Canon佳能原厂的EF镜头系列非常庞大包括广角、标准、远摄、微距等多种类型的镜头。 5. 第三方适配器通过使用适配器其他品牌的镜头也可以安装在佳能EF卡口相机上。例如佳能推出了EF-EOS R 0.71x卡口适配器允许在EOS R系列相机上使用EF镜头。因此当我们打开“狗东”准备给自己的新相机买镜头的时候就不难发现我们需要根据自己相机的品牌来挑选特定卡口的镜头这样的镜头才能被我们的相机正常驱动。回到Java上面来说其实接口给我们带来的最大的好处就是“解耦”了相机能够搭配不同的镜头才能有各种各样的搭配玩法变得更加的灵活。在软件系统中也是一样的接口可以有很多不同“特色”的实现类我们只需要声明同一个接口却可以引用很多个该“接口”引申出来的“子类”这不也大大增强了我们软件系统中组件的灵活性吗聪明的你对于“接口”的理解是不是又更加的深入了呢接口在编码中的实践本文发表也有些年头了最开始仅仅只是想自己记录一些学习心得没想到竟然受到大家如此热爱陆陆续续看到评论区有些同学可能因为还没有实际的工作经验所以对接口在实际项目中的应用还是缺少些感性的认知因此本着宠粉的精神觉得可以通过模拟【发送短信】这个场景来给到工作经验少的同学对于接口有一个更加感性的认知。假设你刚参加实习工作组长说来来来先给你个小需求练练手我们系统现在需要接入短信平台你仔细看看阿里云的文档把阿里云SDK引入我们系统然后大概有100处地方需要发送短信你把发送短信的代码分别加到这100处去。好家伙这不就是CTRLCV的事情吗?于是你看到了阿里云发送短信只需要一个class就能完成工作这个class长下面这样package com.lyj.demo.sms; /** * 阿里云短信实现类 */ public class AliyunSMS { /**发送登录短信 * param phoneNumbers 电话号码 * param message 短信内容 */ void sendLoginSMS(String phoneNumbers,String message) { System.out.println(【阿里云】登录短信发送给phoneNumbers:message); } /** * 忘记密码发送短信 * * param phoneNumbers 电话号码 * param message 短信内容 */ void sendForgetSMS(String phoneNumbers,String message) { System.out.println(【阿里云】忘记密码发送给phoneNumbers:message); } /**发送营销短信 * param phoneNumbers 电话号码 * param message 短信内容 */ void sendMarketingSMS(String phoneNumbers, String message) { System.out.println(【阿里云】营销短信发送给phoneNumbers:message); } }好家伙100处代码分散在项目中各个文件里面虽然下图100条发送语句都在一个文件中但模拟100条发送语句分散在各种代码文件中光打开这些文件都耗费了你一个下午的时间终于在快下班的时候你感叹到小小短信平台拿下你跑了跑项目看到发送的短信内容露出了欣慰的笑容。【阿里云】登录短信发送给15067471274:您的登录短信验证码为231453 【阿里云】忘记密码发送给15412345678:您的忘记密码验证码为341531 【阿里云】营销短信发送给13875232346:今晚20点优惠多多限时抢购 【阿里云】登录短信发送给15067471274:您的登录短信验证码为231453 【阿里云】忘记密码发送给15412345678:您的忘记密码验证码为341531 【阿里云】营销短信发送给13875232346:今晚20点优惠多多限时抢购 【阿里云】登录短信发送给15067471274:您的登录短信验证码为231453 【阿里云】忘记密码发送给15412345678:您的忘记密码验证码为341531 【阿里云】营销短信发送给13875232346:今晚20点优惠多多限时抢购 【阿里云】登录短信发送给15067471274:您的登录短信验证码为231453 【阿里云】忘记密码发送给15412345678:您的忘记密码验证码为341531 【阿里云】营销短信发送给13875232346:今晚20点优惠多多限时抢购正当你准备下班和女朋友约饭的时候小组长来了说“完成的不错但是领导觉得阿里云太贵了我们还是准备用腾讯云把阿里云换成腾讯云吧明天就要上线哦”你笑着对小组长说“好的我今晚没事放心我加个班一下子就能搞定的事情”心里却想着vocal !这B组长一下班就搞事情是吧看我10分钟就能搞定今晚和女朋友的饭局稳稳地说着你看着代码却发现代码散落在各个文件中你不禁陷入了沉思这咋改啊阿里云和腾讯云的短信参数顺序也不一样名字也不一样看来只能一个一个替换了说罢你便开始一个一个代码的删除新增忙的手忙脚乱。下面是腾讯云发送短信的class:package com.lyj.demo.sms; /** * 腾讯云短信实现类 */ public class TencentSMS { /** * /**发送登录短信 * * param message 短信内容 * param phoneNumbers 电话号码 */ void sendLoginSMS(String message, String phoneNumbers) { System.out.println(【腾讯云】登录短信发送给phoneNumbers:message); } /** * 忘记密码发送短信 * * param message 短信内容 * param phoneNumbers 电话号码 */ void sendForgetSMS(String message, String phoneNumbers) { System.out.println(【腾讯云】忘记密码发送给phoneNumbers:message); } /** * 发送营销短信 * * param message 短信内容 * param phoneNumbers 电话号码 */ void sendMarketingSMS(String message, String phoneNumbers) { System.out.println(【腾讯云】营销短信发送给phoneNumbers:message); } }你直接通过ctrlR把阿里云替换成腾讯云一跑项目发现全是Bug,原来腾讯云的参数和阿里云全部是反的你直接人傻了这可咋办啊眼泪在眼眶里打转。此时小组长看到你难堪的样子说到“你忘记你学的接口吗试试看能不能用它去解决问题”。此时你心里想到“接口接口这破玩意儿有啥用”以下引用的是本文真实的评论哈哈有个问题想不明白接口由不同的类去实现我干嘛不直接写几个类为什么非要实现接口接口里面屁也没有就定义了几个方法名。就好比人是一个类你非要定义一个接口规定了吃饭、拉屎、睡觉等等方法然后去实现这些方法有人用刀叉吃饭有人用手抓有人用筷子。我干嘛不直接印度人定义一个类中国人定义一个类美国人定义一个类呢想不通在我看来接口屁用没用。那么我们看看怎样用接口去实现呢小组长说既然腾讯云和阿里云有不同的地方是不是也有相同的地方即共性的地方我们把共性的地方即接收一个号码参数一个短信内容参数最后发送出去。这样一个抽取成公共的接口散落各个文件的100处代码调用都直接调用接口而不是具体的实现类阿里云或腾讯云这样后续我们无论变成什么短信平台都不会需要去找到这100处代码去做修改因为他们依赖的是抽象的接口不变的抽象。下面是基于阿里云和腾讯云抽取出来的公共的短信接口CommonSmsServicepackage com.lyj.demo.sms; public interface CommonSmsServiceInterface { /**发送登录短信 * param phoneNumbers 号码 * param message 短信 */ void sendLoginSMS(String phoneNumbers,String message); /** * 忘记密码发送短信 * * param phoneNumbers 电话号码 * param message 短信内容 */ void sendForgetSMS(String phoneNumbers,String message) ; /**发送营销短信 * param phoneNumbers 电话号码 * param message 短信内容 */ void sendMarketingSMS(String phoneNumbers, String message); }阿里云实现CommonSmsService这个接口的类AliyunSmsServiceImplpackage com.lyj.demo.sms; public class AliyunSmsServiceInterfaceImpl implements CommonSmsServiceInterface { private final AliyunSMS aliyunSMS; public AliyunSmsServiceInterfaceImpl(AliyunSMS aliyunSMS) { this.aliyunSMS aliyunSMS; } Override public void sendLoginSMS(String phoneNumbers, String message) { aliyunSMS.sendLoginSMS(phoneNumbers, message); } Override public void sendForgetSMS(String phoneNumbers, String message) { aliyunSMS.sendForgetSMS(phoneNumbers, message); } Override public void sendMarketingSMS(String phoneNumbers, String message) { aliyunSMS.sendMarketingSMS(phoneNumbers, message); } }腾讯云实现 CommonSmsService这个接口的实现类TencentSmsServiceImpl(此处要注意腾讯云的参数是反的哈实现类里就要把他纠正过来)package com.lyj.demo.sms; public class TencentSmsServiceInterfaceImpl implements CommonSmsServiceInterface { private final TencentSMS tencentSMS; public TencentSmsServiceInterfaceImpl(TencentSMS tencentSMS) { this.tencentSMS tencentSMS; } Override public void sendLoginSMS(String phoneNumbers, String message) { tencentSMS.sendLoginSMS(message,phoneNumbers); } Override public void sendForgetSMS(String phoneNumbers, String message) { tencentSMS.sendForgetSMS(message,phoneNumbers); } Override public void sendMarketingSMS(String phoneNumbers, String message) { tencentSMS.sendMarketingSMS(message.phoneNumbers); } }此时分散在各个文件中的100处代码就可以写成下面这样如果你的小组长在“恶心”你你再也不需要改100代码了只需要改下面两行代码这样此时你还会觉得接口没有用吗原来要改100处的任务使用接口后只需要改2处而且大大减少修改代码导致的bug问题此时聪明的你还会觉得【接口】是鸡肋了吗“依赖抽象而不是具体实现”是面向对象编程中的一条核心原则它强调在设计和实现软件系统时应该依赖于抽象的接口或抽象类而不是依赖于具体的实现类。这个原则有助于提高代码的灵活性、可维护性和可测试性。下面是这个原则的一些关键点 1. 接口隔离定义清晰的接口使得客户端代码只依赖于它们需要的特定功能而不是依赖于一个庞大的、多功能的类。 2. 开闭原则软件实体应当对扩展开放对修改封闭。这意味着当需要增加新功能时可以通过继承或实现新的抽象接口来扩展系统而不需要修改现有的代码。 3. 单一职责每个类应该只有一个引起它变化的原因这通常意味着每个类应该只负责一个具体的功能。 4. 替换性由于依赖的是抽象所以具体的实现可以被替换只要它们遵循相同的接口或抽象类。 5. 解耦抽象层次上的依赖关系使得各个组件之间的耦合度降低从而更容易地进行修改和替换。 6. 控制反转依赖抽象而不是具体实现是控制反转IoC的基础其中对象的创建和它们之间的依赖关系由外部容器管理而不是由对象自身管理。 7. 依赖注入这是实现依赖抽象的一种方式通过将依赖关系在运行时注入到对象中而不是在对象内部创建。 通过遵循“依赖抽象而不是具体实现”的原则开发者可以构建出更加模块化、灵活和可维护的系统。这种设计方式在现代软件开发中非常普遍特别是在使用面向对象编程和设计模式的场合。说真的这两年看着身边一个个搞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大模型学习资源包》免费分享