博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring深度学习 — 关于 Spring
阅读量:37194 次
发布时间:2020-08-01

本文共 11350 字,大约阅读时间需要 37 分钟。

前言


作为一名Java 程序猿,相信对 Spring 都不陌生,那么我们经常使用的 Spring的发展史大家都了解过吗?它是如何来的?又是如何一步一步成长到了现在这种不可替代的重要地位?下面将对 Spring 进行一个整体认知和学习,对后面的深度学习起到铺垫作用。本文意在对知识点的温顾,如文中有写的不对的地方,还望不吝指教。

一、Spring 的发展史

        相信经历过不使用框架开发 Web 项目的70 后、80 后都会高如此感触 ,如今的程序员开发项目太轻松了 ,基本只需要关心业务如何实现 ,通用技术问题只需要集成框架便可。早在 2007 年 ,一个基于 Java 语言的开源框架正式发布 ,取了一个非常有活力且美好的名字 ,叫做 Spring。它是一个开源的轻量级 Java SE ( Java 标准版本 ) /Java EE ( Java 企业版本 ) 开发应用框架 ,其目的是用于简化企业级应用程序开发。应用程序是由一组相互协作的对象组成。而在传统应用程序开发中 ,一个完整的应用是由一组相互协作的对象组成。所以开发一个应用除了要开发业务逻辑之外  ,最多的是关注如何使这些对象协作来完成所需功能,而且要低耦合、高聚合。业务逻辑开发是不可避免的,那如果有个框架出来帮我们来创建对象及管理这些对象之间的依赖关系。可能有人说了 ,比如 ”抽象工厂、工厂方法模式” 不也可以帮我们创建对象 ,“生成器模式” 帮我们处理对象间的依赖关系 ,不也能完成这些功能吗 ?可是这些又需要我们创建一些工厂类、生成器类 ,我们又要管理这些类 ,增加了我们的负担 ,如果能有种通过配置方式来创建对象 ,管理对象之间依赖关系 ,我们不需要通过工厂和生成器来创建及管理对象之间的依赖关系 ,这样我们是不是减少了许多工作 ,加速了开发 ,能节省出很多时间来干其他事。Spring 框架刚出来时主要就是来完成这个功能。

        Spring 框架除了帮我们管理对象及依赖关系 ,还提供像通用日志记录、性能统计、安全控制、异常处理等面向切面的能力 ,还能帮我管理最头疼的数据库事务 ,本身提供了一套简单的 JDBC 访问实现 , 提供与第三方数据访问框架集成 ( 如 Hibernate、JPA ),与各种 Java EE 技术整合 ( 如 Java Mail、任务调度等 ) ,提供一套自己的Web层框架 Spring MVC、而且还能非常简单的与第三方 Web 框架集成。从这里我们可以认为 Spring 是一个超级粘合大平台 ,除了自己提供功能外 ,还提供粘合其他技术和框架的能力  ,从而使我们可以更自由的选择到底使用什么技术进行开发。而且不管是 JAVA  SE   (  C/S 架构 ) 应用程序还是 JAVA EE ( B/S 架构 ) 应用程序都可以使用这个平台进行开发。如今的 Spring 已经不再是一个框架 ,早已成为了一种生态。SpringBoot  的便捷式开发实现了零配置  ,SpringCloud   全家桶 ,提供了非常方便的解决方案。接下来,让我们来深入探讨Spring 到底能给我们带来什么 ?

二、一切从 Bean 开始

        说到 Bean这个概念 ,还得从 Java 的起源说起。早在 1996 年 ,Java 还只是一个新兴的、初出茅庐的编程语言。人们之所以关注它仅仅是因为 ,可以使用 Java 的Applet 来开发 Web 应用 ,作为浏览器组件。但开发者们很快就发现这个新兴的语言还能做更多的事情。与之前的所有语言不同 ,Java 让模块化构建复杂的系统成为可能 ( 当时的软件行业虽然在业务上突飞温猛进,但当时开发用的是传统的面向过程开发思想 ,软件的开发效率一直踟蹰不前。伴随着业务复杂性的不断加深 ,开发也变得越发困难。其实 ,当时也是 OOP 思想飞速发展的时期 ,它在 80 年代末被提出 ,成熟于 90 年代 ,现今大多数编程语言都已经是面向对象的 )。

        同年 12 月 ,Sun 公司发布了当时还名不见经传但后来人尽皆知的JavaBean 1.00-A 规范。早期的 JavaBean 规范针对于 Java ,它定义了软件组件模型。这个规范规定了一整套编码策略 ,使简单的Java 对象不仅可以被重用 ,而且还可以轻松地构建更为复杂的应用。尽管 JavaBean 最初是为重用应用组件而设计的 ,但当时他们却是主要用作构建窗体控件 ,毕竟在 PC 时代那才是主流。但相比于当时正如日中天的 Delphi、VB 和 C++ ,它看起来还是太简易了 ,以至于无法胜任任何”实际的”工作需要。

        复杂的应用通常需要事务、安全、分布式等服务的支持 ,但 Java Bean 并未直接提供。所以到了1998 年 3 月 ,Sun 公司发布了EJB 1.0 规范 ,该规范把 Java 组件的设计理念延伸到了服务器端 ,并提供了 许多必须的企业级服务 ,但它也不再像早期的Java Bean 那么简单了。实际上 ,除了名字叫 EJB Bean 以外 ,其他的和 JavaBean 关系不大了。

        尽管现实中有很多系统是基于 EJB 构建的 ,但 EJB 从来没有实现它最初的设想 :简化开发。EJB 的 声明式编程模型的确简化了很多基础架构层面的开发 ,例如事务和安全 ;但另一方面 EJB 在部署描述符和配套代码实现等方面变得异常复杂。随着时间的推移 ,很多开发者对 EJB 已经不再抱有幻想 ,开始寻求更简洁的方法。

        现在 Java 组件开发理念重新回归正轨。新的编程技术 AOP 和 DI 的不断出现 ,他们为 JavaBean 提 供了之前 EJB 才能拥有的强大功能。这些技术为 POJO 提供了类似 EJB 的声明式编程模型 ,而没有引入任何 EJB  的复杂性。当简单的Java Bean 足以胜任时 ,人们便不愿编写笨重的 EJB 组件了。

        客观地讲 ,EJB 的发展甚至促进了基于 POJO 的编程模型。引入新的理念 ,最新的 EJB 规范相比之前的规范有了前所未有的简化 ,但对很多开发者而言 ,这一切的一切都来得太迟了。到了EJB 3 规范发布时 ,其他基于 POJO 的开发架构已经成为事实的标准了 ,而 Spring 框架也就是这样的大环境下出现的。

三、Spring 的设计初衷

        Spring 是为解决企业级应用开发的复杂性而设计 ,它可以做很多事。但归根到底支撑 Spring 的仅仅是少许的基本理念 ,而所有的这些基本理念都能可以追溯到一个最根本的使命 :简化开发。这是一个郑重的承诺 ,其实许多框架都声称在某些方面做了简化。而 Spring 则立志于全方面的简化 Java 开发。

对此 ,她主要采取了4 个关键策略 :

1、基于 POJO 的轻量级和最小侵入性编程 ;

2、通过依赖注入和面向接口松耦合 ;

3、基于切面和惯性进行声明式编程 ;

4、通过切面和模板减少样板式代码  ;

 而它主要是通过 :面向 Bea n(BOP)、依赖注入 ( DI ) 以及面向切面 ( AOP ) 这三种方式来达成的。

四、BOP编程

        Spring 是面向 Bean 的编程 ( Bea n Oriented Programming, BOP ) , Bean 在 Spring 中才是真正的主角。Bean在Spring 中作用就像Object 对OOP 的意义一样 ,Spring 中没有 Bean也就没有Spring 存在的意义。Spring  提供了IOC 容器通过配置文件或者注解的方式来管理对象之间的依赖关系。

        控制反转(其中最常见的实现方式叫做依赖注入 ( Dependency lnjection , DI ) ,还有一种方式叫 ”依赖查找”  ( Dependency Lookup , DL ), 它在 C++、Java、PHP 以及.NET 中都运用。在最旱的 Spring 中是包含有依赖注入方法和依赖查询的 ,但因为依赖查询使用频率过低 ,不久就被 Spring 移除 了 ,所以在 Spring 中控制反转也被直接称作依赖注入) ,它的基本概念是 :不创建对象 ,但是描述创建它们的方式。在代码中不直接与对象和服务连接 ,但在配置文件中描述哪一个组件需要哪一项服务。容器 ( 在 Spring  框架中是 IOC 容器 ) 负责将这些联系在一起。

        在典型的 IOC 场景中 ,容器创建了所有对象 ,并设置必要的属性将它们连接在一起 ,决定什么时间调用方法。

五、依赖注入的基本概念

        Spring 设计的核心 org.springframework.beans 包 ( 架构核心是 org.springframework.core 包 ), 它的设计目标是与 JavaBean 组件一起使用。这个包通常不是由用户直接使用 ,而是由服务器将 其用作其他多数功能的底层中介。下一个最高级抽象是 BeanFactory 接口,它是工厂设计模式的实现 , 允许通过名称创建和检索对象。BeanFactory也可以管理对象之间的关系。

BeanFactory 最底层支持两个对象模型。

1 、单例 :提供了具有特定名称的全局共享实例对象 ,可以在查询时对其进行检索。Singleton 是默认的也是最常用的对象模型。

2 、原型 :确保每次检索都会创建单独的实例对象。在每个用户都需要自己的对象时 ,采用原型模式。

Bean 工厂的概念是 Spring 作为 IOC 容器的基础。IOC 则将处理事情的责任从应用程序代码转移到框架。

六、AOP编程理念

        面向切面编程 ,即AOP ,是一种编程思想 ,它允许程序员对横切关注点或横切典型的职责分界线的行为 ( 例如日志和事务管理 ) 进行模块化。AOP 的核心构造是方面 ( 切面 ) ,它将那些影晌多个类的行为封装到可重用的模块中。

        AOP 和 IOC 是补充性的技术 ,它们都运用模块化方式解决企业应用程序开发中的复杂问题。在典 型的面向对象开发方式中,可能要将日志记录语句放在所有方法和 Java 类中才能实现日志功能。在 AOP 方式中 ,可以反过来将日志服务模块化 ,并以声明的方式将它们应用到需要日志的组件上。当然 ,优势就是 Java 类不需要知道日志服务的存在 ,也不需要考虑相关的代码。所以,用 Spring AOP 编写的应用程序代码是松散耦合的。

AOP 的功能完全集成到了Spring 事务管理、日志和其他各种特性的上下文中。

AOP 编程的常用场景有 :Authentication( 权限认证 )、Auto Caching( 自动缓存处理 )、Error Handling( 统一错误处理 ) 、Debugging ( 调试信息输出 ) 、Logging ( 日志记录 ) 、Transactions ( 事务处理 )

七、Spring 中的编程思想

Spring 思想 应用场景(特点) 一句话归纳
OOP Object Oriented Programming(面向对象编程)用程序归纳总结生活中的一切事务 封装、继承、多态
BOP Bean Oriented Programming(面向 Bean 编程)面向 Bean (普通的 Java 类)设计程序,解放程序员。 一切从 Bean 开始
AOP Aspect Oriented Programming(面向切面编程)找出多个类中有一定规律的代码,开发时拆开,运行时再合并。面向切面编程,即面向规则编程。 解耦,专人做专事
IOC Inversion of Control (控制反转)将 new 对象的动作交给 Spring 管理,并由 Spring 保存已创建的对象(IOC容器)。 转交控制权(即控制权反转)
DI/DL

Dependency Injection(依赖注入)或者 Dependency Lookup(依赖查找)

依赖注入、依赖查找 ,Spring 不仅保存自己创建的对象,而且保存对象与对象之间的关系。注入即赋值,主要三种方式:构造方法、set 方法、直接赋值。

赋值

八、Spring 注解编程

1、Spring Framework 1.x 注解驱动启蒙时代

        从 Spring Framework 1.2.0 版本开始 ,开始支持 Annotation ,虽然框架层面均已支持@managedResource 和@Transactional等 ,但是真主要的还是以XML 配置为准。

2、Spring Framework 2.X 注解驱动过渡时代       

        Spring Framework 2. 在Annotation  支持方面添加了新的成员 ,@Required、数据相关的@Repository 及 AOP 相关的@Aspect 等 ,但同时提升了XML 配置能力 ,即 ”可扩展的XML 编写(Extensible XML authoring)",当然,这种扩展能力的出现,无形中为 XML 的配置增加了筹码。

3、Spring Framework 2.5 开始 ,引入了新的骨架式 Annotation

        @Service、@Controller、@RequestMapping及@ModelAttrbute

        Spring Framework 2.5 还支持了 JSR-250(Java 规范)。

        @Resource 注入

        @PostConstruct 替代<bean init-method="xxx" />

        @PreDestroy 替代 <bean destroy-method="xxx" />

        尽管 Spring Framework 2.X 时代提供了为数不少的注解 ,然而编程的手段却不多 ,最主要的原因在于框架层面仍未 ”直接” 提供驱动注解的 Spring 应用上下文 ,并且仍需要 XML 驱动 ,<context:annotation-config>和 <context:component-scan>

4、Spring Framework 3.x 洼解驱动黄金时代

        Spring Framework 3.x 是一个里程碑式的时代 ,3.0 除了提升 Spring 模式注解 “派生” 的层次性 ,首要任务是替换 XML 配置方式 ,引入配置类注解@Configuration ,该注解是内建的@Component的 ”派生” 注解 ,遗憾的是 ,3.0 并没再引入<context:component-scan>的注解 ,而是选择过渡方案@lmportResource 和@Import。lmportResource 负责导入遗留的XML 配置文件 ,Import 允许导入一个或多个类作为 Spring Bean。

        3.0 引入 AnnotationConfigApplicationContext 作为前时代 AppIicationContext 的替代者。3.1 新引入注解@ComponentScan ,替换 XML 的<context:component-scan> ,成为全面进入注解驱动时代的一大步。

        SpringFramework3.x  注解提升还体现在以下方面 :

        定义声明中 ,@Bean 允许使用注解@Role 设置其角色,使得 Spring 应用上下文具备条件化 Bean 定义的能力方面 ,@RequestHeader , @CookieVale 和@RequestPart 出现 ,使得不必使用 Servlet API 以及配置属性源抽象 PropertySources,奠定了SpringBoot 外部化配置的基础。

        配套的注解 Caching 和 Cacheable 极大简化数据缓存的开发。 周期异步@Schedule 及异步 web 请求 DeferredResuIt。

5、Spring Framework 4.x 注解驱动完善时代

        3.1开始提供@Profile 提供了配置化的条件组装 ,不过这方面还是比较单一的 ,4.0 开始 ,引入条件化注解@Conditional ,通过自定义 Condition 实现配合 ,弥补之前版本条件化装配的短板 ,4.0 开 始 Profile 反过来通过@conditional 实现。

        Java8 开始对提供@Repeatable  , Framework4.0 巧妙的兼容了JSR-310。根据特性 ,将

@PropertySource、@Comp onentScan 提升为可重复使用的注解@PropertySources 、

@Compo nentScans。

        4.2 开始新增了事件监听器注解@Eventlistener ,作为 ApplicationListener 接口编程的第二选择。@AliasFor 解除注解派生的时候冲突限制在浏览器跨域资源访问方面 ,引入@CrossOrigin  ,作为 CorsRegistry  替换注解方案。

6、SpringFramework 5.x 注解驱动成熟时代

        SpringFramework5.0 作为 Spring Boot 2.0 的底层 ,注解驱动的性能提升不是那么明显。在SpringBoot 应用场景中 ,大量使用@ComponentScan 扫描 ,导致 Spring 模式的注解解析时间耗时较长 ,面对这个问题 ,5.0入@Indexed ,为 Spring 模式注解添加索引。

九、Spring5 系统架构

        Spring 总共大约有 20  个模块 ,由 1300 多个不同的文件构成。而这些组件被分别整合在核心容器 ( Core Container )、AOP ( Aspect Oriented Programming ) 和设备支持( lnstrmentation ) 、数据访问及集成 ( Data Access/lntegeration ) 、Web、报文发送 ( Messaging ) 、Test , 6 个模块集合中。以下是  Spring 5 的模块结构图 :

组成 Spring 框架的每个模块集合或者模块都可以单独存在,也可以一个或多个模块联合实现。每个模块的组成和功能如下:

1、核心容器

        由 spring-beans、spring-core、spring-context 和 spring-expression(Spring Expression Language, SpEL)四个模块组成。

        spring-core spring-beans 模块是 spring 框架的核心模块,包含了控制反转(Inversion of  Control, IOC)和依赖注入(Dependency Injection,DI)。BeanFactory 接口是 Spring 框架中的核心接口,它是工厂模式的具体实现。BeanFactory 使用控制反转对应用程序的配置和依赖性规范与实际的应用程序代码进行了分离。但 BeanFactory 容器实例化后并不会自动实例化 Bean ,只有当 Bean 被使用时 BeanFactory 容器才会对该 Bean 进行实例化与依赖关系的装配。

        spring-context 模块构架于核心模块之上 ,它扩展了BeanFactory ,为她添加了Bean 生命周期控制、框架事件体系以及资源加载透明化等功能。此外该模块还提供了许多企业级支持 ,如邮件访问、远程访问、任务调度等 ,AppIicationContext 是该模块的核心接口,它的超类是 BeanFactory。与BeanFactory 不同 ,AppIicationContext 容器实例化后会自动对所有的单实例 Bean 进行实例化与依赖关系的装配 ,使之处于待用状态。

        spring-context-support 模块是对 Spring IOC 容器的扩展支持 ,以及 IOC 子容器。

        spring-context-indexer 模块是 Spring 的类管理组件和 Classpath 扫描。

        spring-expression 模块是统一表达式语言 ( EL ) 的扩展模块 ,可以查询、管理运行中的对象 ,同时也方便的可以调用对象方法、操作数组、集合等。它的语法类似于传统 EL,但提供了额外的功能 ,最出色的要数函数调用和简单字符串的模板函数。这种语言的特性是基于 Spring 产品的需求而设计 ,他可以非常方便地同 Spring IOC 进行交互。

2、AOP 和设备支持

        由 spring-aop、spring-aspects、spring-instrument 3个模块组成。

        spring-aop 是 Spring 的另一个核心模块 ,是AOP 主要的实现模块。作为继 OOP 后 ,对程序员影响最大的编程思想之一 ,AOP 极大地开拓了人们对于编程的思路。在 Spring 中 ,他是以JVM 的动态代理技术为基础 ,然后设计出了一系列的AOP 横切实现 ,比如前置通知、返回通知、异常通知等 ,同时 ,Pointcut 接口来匹配切入点 ,可以使用现有的切入点来设计横切面 ,也可以扩展相关方法根据需求进行切入。

        spring-aspects 模块集成自AspectJ 框架 ,主要是为 Spring AOP 提供多种 AOP 实现方法。

        spring-instrument 模块是基于 JAVA SE 中的 “java.lang.instrument ”进行设计的 ,应该算是 AOP的一个支援模块 ,主要作用是在 JVM 启用时 ,生成一个代理类 ,程序员通过代理类在运行时修改类的字节,从而改变一个类的功能,实现AOP 的功能。在分类里,我把它分在 AOP 模块下,在 Spring 官网文档里对这个地方也没有很明确的指出。

3、数据访问与集成

        由spring-jdbc、spring-tx、spring-orm、spring-jms 和 spring-oxm 5 个模块组成。

        spring-jdbc 模块是 Spring 提供的JDBC 抽象框架的主要实现模块, 用于简化 Spring JDBC 操作 。 主要是提供 JDBC 模板方式、关系数据库对象化方式、SimpleJdbc 方式、事务管理来简化 JDBC 编程 , 主要实现类是 JdbcTemplate、SimpleJdbcTemplate 以及 NamedParameterJdbcTemplate。

        spring-tx 模块是 Spring JDBC 事务控制实现模块。使用 Spring框架 ,它对事务做了很好的封装 , 通过它的AOP 配置 ,可以灵活的配置在任何一层 ;但是在很多的需求和应用 ,直接使用 JDBC 事务控制还是有其优势的。其实 ,事务是以业务逻辑为基础的 ;一个完整的业务应该对应业务层里的一个方法 ; 如果业务操作失败 ,则整个事务回滚 ;所以,事务控制是绝对应该放在业务层的 ;但是 ,持久层的设计则应该遵循一个很重要的原则 :保证操作的原子性 ,即持久层里的每个方法都应该是不可以分割的。所以,在使用 Spring JDBC 事务控制时 ,应该注意其特殊性。

        spring-orm 模块是 ORM 框架支持模块 ,主要集成 Hibernate, Java Persistence API (JPA) 和Java Data Objec ts (JDO) 用于资源管理、数据访问对象(DAO)的实现和事务策略。

        spring-oxm 模块主要提供一个抽象层以支撑 OXM ( OXM 是 Object-to-XML-Mapping 的缩写 , 它是一个 O/M-mapper ,将java 对象映射成 XML 数据 ,或者将 XML 数据映射成java 对象 ) ,例如 : JAXB, Castor, XMLBeans, JiBX 和 XStream 等。

        spring-jms 模块 ( Java Messaging Service ) 能够发送和接收信息 ,自Spring Framework 4.1 以后  ,他还提供了对  spring-messaging 模块的支撑。

4、Web组件

        由spring-web, spring-webmvc 、spring-websocket 和spring-webflux 4 个模块组成。

        spring-web 模块为 Spring 提供了最基础 Web 支持 ,主要建立于核心容器之上 ,通过 Servlet 或者 Listeners 来初始化 IOC 容器 ,也包含一些与 Web 相关的支持。

        spring-webmvc  模块众所周知是一个的Web-Servlet  模块 ,实现了Spring  MVC (  model-view-Controller  ) 的Web 应用。

        spring-websocket 模块主要是与 Web 前端的全双工通讯的协议。

        spring-webflux 是一个新的非阻塞函数式 Reactive Web 框架 ,可以用来建立异步的 ,非阻塞 , 事件驱动的服务 ,并且扩展性非常好。这也是 Spring5 中推出的全新模式,可以抛弃Servlet来独立使用。

5、通信报文

        即spring-messaging模块 ,是从 Spring4 开始新加入的一个模块 ,主要职责是为 Spring 框架集成一些基础的报文传送应用。

6、集成测试

        即spring-test 模块 ,主要为测试提供支持的 ,毕竟在不需要发布( 程序 )到你的应用服务器或者连接到其他企业设施的情况下能够执行一些集成测试或者其他测试对于任何企业都是非常重要的。

7、集成兼容

        即spring-framework-bom 模块 ,Bi11 of MateriaIs. 解决 Spring 的不同模块依赖版本不同问题。

十、Spring 版本命名规则

        常见软件的版本号命名

软件 升级过程 说明
Linux Kernel

0.0.1

1.0.0

2.6.32

...

若用XYZ表示,则偶数 Y表示稳定版本,奇数 Y表示开发版本
Windows

Windows98

Windows2000

WindowsXP

Windows7

...

最大的特点是杂乱无章,毫无规律
SSH Client 0.9.8
OpenStack

2014.1.3

2015.1.1.dev8

从上可以看出,不同的软件版本好风格 各异,随着系统的规模越大,依赖的软件越多,如果这些软件没有遵循一套规范的命名风格,容易造成 Dependency Hell。所以当我们发布版本时 ,版本号的命名需要遵循某种规则 ,其中 Semantic Versioning 2.0.0 定义了一套简单的规则及条件来约束版本号的配置和增长。下面我们来看一下 Spring 各个版本的命名规则,通过版本号的认识,方便后续小伙伴们获取对应版本的内容,可以读懂到底是干啥的。

Spring 版本命名规则

描述方式 说明 含义
Snapshot 快照版 尚不稳定,处于开发中的版本
Release 稳定版 功能相对稳定,可以对外发行,但有时间限制
GA 正式版 代表广泛可用的稳定版(General Availability)
M 里程碑版 (M是 Milestone 的意思)具有一些全新的功能或是具有里程碑意义的版本。
RC 终测版 Release Candidate (最终测试),即将作为正式版发布。

        通过对本篇文章的学习,可以从整体了解 Spring 的大体内容,方便后续对相关内容的具体学习。

转载地址:http://yupwwy.baihongyu.com/

你可能感兴趣的文章
HDU1233(基础最小生成树 prim和 kruskal)
查看>>
终于找到可以一文多发的平台了!
查看>>
IntelliJ IDEA 2019 快捷键终极大全,速度收藏!
查看>>
第3章-5 字符转换 (15分)【python】
查看>>
L1-068 调和平均 (10 分)
查看>>
L1-069 胎压监测 (15 分)
查看>>
L1-071 前世档案 (20 分)
查看>>
L1-072 刮刮彩票 (20 分)
查看>>
L2-012 关于堆的判断 (25 分)
查看>>
L1-064 估值一亿的AI核心代码 (20 分)
查看>>
L2-033 简单计算器 (25 分)
查看>>
L2-034 口罩发放 (25 分)
查看>>
L2-019 悄悄关注 (25 分)
查看>>
L1-020 帅到没朋友 (20 分)
查看>>
L1-046 整除光棍 (20 分)
查看>>
L2-021 点赞狂魔 (25 分)【优化后的】
查看>>
L2-032 彩虹瓶 (25 分)
查看>>
L2-004 这是二叉搜索树吗? (25 分)
查看>>
[Error] ‘nullptr‘ was not declared in this scope解决方案
查看>>
L2-011 玩转二叉树 (25 分)
查看>>