当前位置: 首页 > news >正文

科普文:Lombok使用及工作原理详解

1. 概叙

Lombok是什么?

  1. Project Lombok 是一个 JAVA 库,它可以自动插入编辑器和构建工具,为您的 JAVA 锦上添花。
  2. 再也不要写另一个 getter/setter 或 equals 等方法,只要有一个注注解,你的类就有一个功能齐全的生成器,自动记录变量,等等。

官方地址:https://projectlombok.org/

Lombok是一种Java™实用工具,可用来帮助开发人员消除Java的冗长代码,尤其是对于简单的Java对象(POJO)。它通过注释实现这一目的

首先Lombok是一款Java IDE的应用工具插件,一个可以通过简单的注解形式来帮助我们简化消除一些必须有但显得很臃肿的Java代码的工具,比如属性的构造器、getter、setter、equals、hashcode、toString方法。结合IDE,通过使用对应的注解,可以在编译源码的时候生成对应的方法。

通过在开发环境中实现Lombok,开发人员可以节省构建诸如hashCode()和equals()这样的方法以及以往用来分类各种accessor和mutator的大量时间。

虽然上述的那些常用方法IDE都能生成,但是lombok更加简洁与方便,能够达到的效果就是在源码中不需要写一些通用的方法,但是在编译生成的字节码文件中会帮我们生成这些方法,这就是lombok的神奇作用。

lombok插件安装

使用的IDE是Intellij idea,编译器需要在

preference->plugins->Browse repositories

搜索lombok,然后安装plugins,需要稍等片刻

添加jar包

在项目中添加lombok的jar包,笔者用的是maven,所以在pom文件中添加了如下的依赖。gradle使用见官网。

<dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><version>1.16.16</version><scope>provided</scope>
</dependency>

常用的注解

官网注解介绍:Stable

2. Lombok原理介绍

2.1 Java类文件编译过程

首先,我们知道 Lombok 功能是作用在类编译时期,那我们来看下一个类编译的过程。

  1. 定义一个 PersonDTO.Java 类

代码语言:javascript

复制

public class PersonDTO {//姓名private String name;  
}
  1. Javac PersonDTO.Java 对源代码进行解析转化,会生成一棵抽象语法树( AST );
  2. 运行过程中会调用实现了 JSR 269 注解处理器,下面介绍;
  3. JSR 实现可处理自定义逻辑,包括可修改编译后的抽象语法树(AST);
  4. Javac 使用修改后的抽象语法树(AST)生成字节码文件;

过程如下图:

AST 是抽象语法树(Abstract Syntax Tree) 的缩写,是 JAVA 源代码展示的一种树状结构它将代码的结构和语法元素映射到树节点上,使得程序可以在编译、

分析和转换过程中更容易地操作和理解。有兴趣可以学习 JavaParser 源码, 了解将 Java 源代码解析生成成一个抽象语法树( AST ),这个树形结构表示了代码的

语法结构包括类、方法、变量、语句等等过程。

github地址:https://github.com/javaparser/javaparser.

如: PersonDTO.Java 在 idea 中使用可视化工具展示文件 AST 树

2.2 JSR 269介绍

首先 JSR 269全称" Pluggable Annotation Processing API ",是 JAVA 平台的一项规范,也被称之为注解处理器 API 。在Java6引入,用于在编译时处理

注解,目标是提供更丰富的编译时元数据处理能力,以增强Java编译器的功能。这个规范允许开发人员创建自定义的注解处理器,这些处理器可以在编译时检查、分析和生成Java代码。

JSR 269在JDK6中被引入,作为APT的替代方案。javac执行的时候会调用Pluggable Annotation Processing API,因此我们可以通过实现此API来改变编译期的一些行为从而达到目的。具体的编译流程如下:

javac编译流程

举例来说,现在有一个实现了Pluggable Annotation Processing API的程序A,那么使用javac编译时的具体流程如下:

1. javac编译器对源码进行分析,生成一个抽象的语法树(AST)

2. javac编译器运行A程序

3. A程序完成逻辑,一般是修改此语法树

4. javac使用修改后的语法树生成可执行的字节码文件

Lomok便是通过Pluggable Annotation Processing API来实现代码生成的。

应用框架:

  1. Servlet、JAX-RS(RESTful Web服务)JSR 269 来生成用于处理 HTTP 请求的代码。
  2. Spring Boot 项目中以处理各种自定义注解,如 @Controller、@Service、@Repository 等。这些注解可以用于自动化配置、依赖注入等方面。
  3. Hibernate 它使用 JSR 269 来处理 JPA 注解,并生成与数据库交互的代码。
  4. Lombok 是一个 JAVA 库,它通过注解处理器生成常见的 JAVA 代码,如 getter、setter、equals、hashCode 等,以简化开发工作。
  5. MapStruct 是一个用于对象映射的 JAVA 库,它使用 JSR 269 来生成类型安全的映射代码,帮助开发人员将一个对象映射到另一个对象。

如何实现自定义注解注解处理器:

1.声明自定义注解;如 Lombok 下的 @Data,@Getter,@Setter等。

2.实现 Process接口,或者继承 AbstractProcessor 复写 process 方法,处理自定义注解逻辑。

代码语言:javascript

复制

import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.*;
import java.util.Set;@SupportedAnnotationTypes("com.example.MyAnnotation") // 自定义注解
@SupportedSourceVersion(SourceVersion.RELEASE_8) //支持的Java版本
public class MyAnnotationProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv)  {// 在这里处理自定义注解,生成代码或执行其他任务return true;}
}

3.注册注解处理器

两种方式:

  1. Resource 文件:项目 META-INF/services 创建 javax.annotation.processing.Processor 文件,自定义注解处理器的全类名写到此文件中。
  2. 通过谷歌工具包 auto-service ,可自动生成以上配置文件。

代码语言:javascript

复制

<!-- 编译注解执行注册 jar包-->
<dependency><groupId>com.google.auto.service</groupId><artifactId>auto-service</artifactId><version>1.0.1</version>
</dependency> @AutoService(Processor.class) //谷歌工具包方式:注册注解处理器
@SupportedAnnotationTypes("com.example.MyAnnotation") // 自定义注解
@SupportedSourceVersion(SourceVersion.RELEASE_8) //支持的Java版本
public class MyAnnotationProcessor extends AbstractProcessor {@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {// 在这里处理自定义注解,生成代码或执行其他任务return true;}
}

2.3 Lombok 实现原理

1. Lombok 实际就是结合注解处理器和 AST 技术, Lombok 实现的注解处理器会遍历 AST ,查找与 Lombok 注解相关的元素,根据注解的要求生成新的代码。

2.编译前后的 AST 语法树对比

加入@Getter注解编译后

3. Lombok 注解处理器,采用 Resource 方式注册编译注解处理器

注解处理器 AnnotationProcessor 源码:

代码语言:javascript

复制

class AnnotationProcessorHider {public static class AstModificationNotifierData {public volatile static boolean lombokInvoked = false;}public static class AnnotationProcessor extends AbstractProcessor {// 获取支持的注解类型@Overridepublic Set<String> getSupportedOptions() {return instance.getSupportedOptions();}// 获取支持的注解类型@Overridepublic Set<String> getSupportedAnnotationTypes() {return instance.getSupportedAnnotationTypes();}// 支持的JDK版本@Overridepublic SourceVersion getSupportedSourceVersion() {return instance.getSupportedSourceVersion();}//初始化环境@Overridepublic void init(ProcessingEnvironment processingEnv) {disableJava9SillyWarning();AstModificationNotifierData.lombokInvoked = true;instance.init(processingEnv);super.init(processingEnv);}// 处理自定义注解逻辑@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {return instance.process(annotations, roundEnv);}}

自定义注解处理器 Handler : 在 Jar 包的 lombok.javac.handlers下,每个注解处理对应一个 Handler. 如 HadlerGetter.java 操作 AST 树生成 getter 方法.

2.4手动实现一个 @Getter 功能

2.4.1.创建 maven 工程 demo 包含两个子模块 getter/getter-use

2.4.2. getter 工程

pom文件:

代码语言:javascript

复制

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>demo</artifactId><groupId>com.example</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>getter</artifactId><dependencies><!-- 注解执行器依赖jar --><dependency><groupId>com.sun</groupId><artifactId>tools</artifactId><version>1.6.0</version><scope>system</scope><systemPath>${java.home}/../lib/tools.jar</systemPath></dependency><!-- 编译注解执行注册 --><dependency><groupId>com.google.auto.service</groupId><artifactId>auto-service</artifactId><version>1.0.1</version></dependency></dependencies>
</project>

自定义 GetterTest 注解

代码语言:javascript

复制

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;/*** @author zcy1*/
@Retention(RetentionPolicy.SOURCE)
@Target(ElementType.TYPE)
public @interface GetterTest {
}

GetterTest 编译注解处理器 GetterProcessor

代码语言:javascript

复制

import com.google.auto.service.AutoService;
import com.sun.source.tree.Tree;
import com.sun.tools.javac.api.JavacTrees;
import com.sun.tools.javac.code.Flags;
import com.sun.tools.javac.code.Type;
import com.sun.tools.javac.processing.JavacProcessingEnvironment;
import com.sun.tools.javac.tree.JCTree;
import com.sun.tools.javac.tree.TreeMaker;
import com.sun.tools.javac.tree.TreeTranslator;
import com.sun.tools.javac.util.*;import javax.annotation.processing.*;
import javax.lang.model.SourceVersion;
import javax.lang.model.element.Element;
import javax.lang.model.element.TypeElement;
import javax.tools.Diagnostic;
import java.util.Set;/*** @author zcy1*/
@AutoService(Processor.class) //谷歌工具包方式:注册注解处理器
@SupportedSourceVersion(SourceVersion.RELEASE_8)
@SupportedAnnotationTypes("GetterTest")
public class GetterProcessor extends AbstractProcessor {/*** 用于在编译器打印消息的组件*/private Messager messager;/*** 提供待处理抽象语法树*/private JavacTrees trees;/*** 用来构造语法树节点*/private TreeMaker treeMaker;/*** 用于创建标识符的对象*/private Names names;/*** 获取一些注解处理器执行处理逻辑时一些关键对象* @param processingEnv 处理环境*/@Overridepublic synchronized void init(ProcessingEnvironment processingEnv) {super.init(processingEnv);this.messager = processingEnv.getMessager();this.trees = JavacTrees.instance(processingEnv);Context context = ((JavacProcessingEnvironment) processingEnv).getContext();this.treeMaker = TreeMaker.instance(context);this.names = Names.instance(context);}@Overridepublic boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) {// 获取自定义GetterTest注解的类Set<? extends Element> elementsAnnotatedWith = roundEnv.getElementsAnnotatedWith(GetterTest.class);elementsAnnotatedWith.forEach(e -> {JCTree tree = trees.getTree(e);tree.accept(new TreeTranslator() {@Overridepublic void visitClassDef(JCTree.JCClassDecl jcClassDecl) {List<JCTree.JCVariableDecl> jcVariableDeclList = List.nil();// 在抽象树中找出所有的成员变量for (JCTree jcTree : jcClassDecl.defs) {if (jcTree.getKind().equals(Tree.Kind.VARIABLE)) {JCTree.JCVariableDecl jcVariableDecl = (JCTree.JCVariableDecl) jcTree;jcVariableDeclList = jcVariableDeclList.append(jcVariableDecl);}}// 对于变量进行生成getter方法的操作jcVariableDeclList.forEach(jcVariableDecl -> {messager.printMessage(Diagnostic.Kind.NOTE, jcVariableDecl.getName() + " has been processed");jcClassDecl.defs = jcClassDecl.defs.prepend(createGetterMethod(jcVariableDecl));});super.visitClassDef(jcClassDecl);}});});return true;}private JCTree.JCMethodDecl createGetterMethod(JCTree.JCVariableDecl jcVariableDecl) {ListBuffer<JCTree.JCStatement> statements = new ListBuffer<>();// 生成表达式 this.name = nameJCTree.JCExpressionStatement aThis = makeAssignment(treeMaker.Select(treeMaker.Ident(names.fromString("this")),               jcVariableDecl.getName()), treeMaker.Ident(jcVariableDecl.getName()));        statements.append(aThis);JCTree.JCBlock block = treeMaker.Block(0, statements.toList());// 生成入参 (String name)JCTree.JCVariableDecl param = treeMaker.VarDef(treeMaker.Modifiers(Flags.PARAMETER),jcVariableDecl.getName(), jcVariableDecl.vartype, null);List<JCTree.JCVariableDecl> parameters = List.of(param);// 生成返回对象 voidJCTree.JCExpression methodType = treeMaker.Type(new Type.JCVoidType());//生成方法名 getNameName methodName = getMethodName(jcVariableDecl.getName());// 返回语法树对象return treeMaker.MethodDef(treeMaker.Modifiers(Flags.PUBLIC),methodName, methodType,   List.nil(),parameters, List.nil(), block, null);}/*** 驼峰方法名*/private Name getMethodName(Name name) {String s = name.toString();return names.fromString("get" + s.substring(0, 1).toUpperCase() + s.substring(1, name.length()));}private JCTree.JCExpressionStatement makeAssignment(JCTree.JCExpression lhs, JCTree.JCExpression rhs) {return treeMaker.Exec(treeMaker.Assign(lhs, rhs));}
}
2.4.4 getter-use工程

pom 文件 引入getter工程

代码语言:javascript

复制

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><parent><artifactId>demo</artifactId><groupId>com.example</groupId><version>0.0.1-SNAPSHOT</version></parent><modelVersion>4.0.0</modelVersion><artifactId>getter-use</artifactId><dependencies><dependency><groupId>com.example</groupId><artifactId>getter</artifactId><version>0.0.1-SNAPSHOT</version></dependency></dependencies>
</project>

PersonDTO 使用@GetterTest

代码语言:javascript

复制

@GetterTest
public class PersonDTO {private String name;private Integer age;
}
2.5.5 项目进行编译

getter 模块下自动生成注册器

getter-use 模块下 PersonDTO.class 可见生成了对应属性的 get 方法

3.总结

本文通过以上对 Lombok 相关介绍,通过对 JAVA 文件编译过程分析和 JSR269 实现的方式, 基于这个规范然后引申出 Lombok 实现原理过程介绍,以及手动实现 getter 案例,想必我们对 Lombok 原理也有了相应的了解。虽然 Lombok 提供了许多便利,由于生成的代码不在源文件中可见,就会导致代码的可读性和维护性较差。在工作中 Lombok 使用时注意闭坑:

问题

解决

@Data 和 @Builder 一起使用时,无参构造方法会被干掉

手动加上注解: @AllArgsConstructor、@NoArgsConstructor。

@Builder 导致类属性默认值无效。

有默认值属性上加注解 : @lombok.Builder.Default。

@Data 生成的 toString 方法,默认能不输出父类属性

子类添加: @ToString(callSuper = true)。

参考文献

Lombok 官网地址: https://projectlombok.org

JavaParser 源码地址: https://github.com/javaparser/javaparser

JAVA 抽象语法树 AST 浅析与使用: https://www.freesion.com/article/4068581927/

相关文章:

科普文:Lombok使用及工作原理详解

1. 概叙 Lombok是什么&#xff1f; Project Lombok 是一个 JAVA 库&#xff0c;它可以自动插入编辑器和构建工具&#xff0c;为您的 JAVA 锦上添花。再也不要写另一个 getter/setter 或 equals 等方法&#xff0c;只要有一个注注解&#xff0c;你的类就有一个功能齐全的生成器…...

飞致云开源社区月度动态报告(2024年7月)

自2023年6月起&#xff0c;中国领先的开源软件公司FIT2CLOUD飞致云以月度为单位发布《飞致云开源社区月度动态报告》&#xff0c;旨在向广大社区用户同步飞致云旗下系列开源软件的发展情况&#xff0c;以及当月主要的产品新版本发布、社区运营成果等相关信息。 飞致云开源大屏…...

mybatis-plus——实现动态字段排序,根据实体获取字段映射数据库的具体字段

前言 前端需要根据表头的点击控件可以排序&#xff0c;虽然前端能根据当前页的数据进行对应字段的排序&#xff0c;但也仅局限于实现当前页的排序&#xff0c;无法满足全部数据的排序&#xff0c;所以需要走接口的查询进行排序&#xff0c;获取最全的排序数据 实现方案 前端…...

redis:Linux安装redis,redis常用的数据类型及相关命令

1. 什么是NoSQL nosql[not only sql]不仅仅是sql。所有非关系型数据库的统称。除去关系型数据库之外的都是非关系数据库。 1.1为什么使用NoSQL ​ NoSQL数据库相较于传统关系型数据库具有灵活性、可扩展性和高性能等优势&#xff0c;适合处理非结构化和半结构化数据&#xff0c…...

JavaScript 和 HTML5 Canvas实现图像绘制与处理

前言 JavaScript 和 HTML5 的 canvas 元素提供了强大的图形和图像处理功能&#xff0c;使得开发者能够在网页上创建动态和交互式的视觉体验。这里我们将探讨如何使用 canvas 和 JavaScript 来处理图像加载&#xff0c;并在其上进行图像绘制。我们将实现一个简单的示例&#xf…...

Java之Java基础二十(集合[上])

Java 集合框架可以分为两条大的支线&#xff1a; ①、Collection&#xff0c;主要由 List、Set、Queue 组成&#xff1a; List 代表有序、可重复的集合&#xff0c;典型代表就是封装了动态数组的 ArrayList 和封装了链表的 LinkedList&#xff1b;Set 代表无序、不可重复的集…...

【C++BFS】1162. 地图分析

本文涉及知识点 CBFS算法 LeetCode1162. 地图分析 你现在手里有一份大小为 n x n 的 网格 grid&#xff0c;上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋&#xff0c;1 代表陆地。 请你找出一个海洋单元格&#xff0c;这个海洋单元格到离它最近的陆地单元格的距…...

实战:安装ElasticSearch 和常用操作命令

概叙 科普文&#xff1a;深入理解ElasticSearch体系结构-CSDN博客 Elasticsearch各版本比较 ElasticSearch 单点安装 1 创建普通用户 #1 创建普通用户名&#xff0c;密码 [roothlink1 lyz]# useradd lyz [roothlink1 lyz]# passwd lyz#2 然后 关闭xshell 重新登录 ip 地址…...

React-Native 宝藏库大揭秘:精选开源项目与实战代码解析

1. 引言 1.1 React-Native 简介 React-Native 是由 Facebook 开发的一个开源框架&#xff0c;它允许开发者使用 JavaScript 和 React 的编程模型来构建跨平台的移动应用。React-Native 的核心理念是“Learn Once, Write Anywhere”&#xff0c;即学习一次 React 的编程模型&am…...

数据结构:二叉树(链式结构)

文章目录 1. 二叉树的链式结构2. 二叉树的创建和实现相关功能2.1 创建二叉树2.2 二叉树的前&#xff0c;中&#xff0c;后序遍历2.2.1 前序遍历2.2.2 中序遍历2.2.3 后序遍历 2.3 二叉树节点个数2.4 二叉树叶子结点个数2.5 二叉树第k层结点个数2.6 二叉树的深度/高度2.7 二叉树…...

召唤生命,阻止轻生——《生命门外》

本书的目的&#xff0c;就是阻止自杀&#xff01;拉回那些深陷在这样的思维当中正在挣扎犹豫的人&#xff0c;提醒他们珍爱生命&#xff0c;让更多的人&#xff0c;尤其是年轻人从执迷不悟的犹豫徘徊中幡然醒悟&#xff0c;回归正常的生活。 网络上抱孩子跳桥轻生的母亲&#…...

JVM:栈上的数据存储

文章目录 一、Java虚拟机中的基本数据类型 一、Java虚拟机中的基本数据类型 在Java中有8大基本数据类型&#xff1a; 这里的内存占用&#xff0c;指的是堆上或者数组中内存分配的空间大小&#xff0c;栈上的实现更加复杂。 Java中的8大数据类型在虚拟机中的实现&#xff1a;…...

C#实战 - C#实现发送邮件的三种方法

作者&#xff1a;逍遥Sean 简介&#xff1a;一个主修Java的Web网站\游戏服务器后端开发者 主页&#xff1a;https://blog.csdn.net/Ureliable 觉得博主文章不错的话&#xff0c;可以三连支持一下~ 如有疑问和建议&#xff0c;请私信或评论留言&#xff01; 前言 当使用 C# 编程…...

数模原理精解【5】

文章目录 二元分布满足要求边际分布条件概率例子1例子2 损失函数概率分布期望值例 参考文献 二元分布 满足要求 连续情况下&#xff0c; φ ( x , y ) \varphi (x,y) φ(x,y)为随机变量 X 、 Y X、Y X、Y的联合概率分布(二元分布)&#xff0c;如果以下条件满足&#xff1a; …...

C语言篇——使用运算符将16进制数据反转

比如&#xff1a;将一个16进制0xFD&#xff0c;即11111101&#xff0c;反向&#xff0c;输出10111111&#xff0c;即0xBF。 #include <stdio.h>unsigned char reverseBits(unsigned char num) {unsigned char reverse_num 0;int i;for (i 0; i < 8; i) {if ((num &…...

2025年和2024CFA一级SchweserKaplan Notes 全集 (内附分享链接)

CFA一级notes百度网盘下载 2024年和2025年 CFA一级考纲已经正式发布&#xff0c;相比与老考纲&#xff0c;新考纲变化实在不算小。 2024年和2025年 CFA一级notes完整版全 https://drive.uc.cn/s/6394c0b6b1a54?public1 2024年和2025年 cfa二级notes完整版全 https://driv…...

B树的实现:代码示例与解析

B树的实现&#xff1a;代码示例与解析 引言 B树是一种自平衡的树数据结构&#xff0c;广泛应用于文件系统和数据库系统中。它是一种多路搜索树&#xff0c;旨在保持数据有序并允许高效的查找、插入和删除操作。本文将深入探讨B树的实现&#xff0c;提供完整的代码示例和详细的…...

HCIA总结

一、情景再现&#xff1a;ISP网络为学校提供了DNS服务&#xff0c;所以&#xff0c;DNS服务器驻留在ISP网络内&#xff0c;而不再学校网络内。DHCP服务器运行在学校网络的路由器上 小明拿了一台电脑&#xff0c;通过网线&#xff0c;接入到校园网内部。其目的是为了访问谷歌网站…...

软件测试_接口测试面试题

接口测试是软件测试中的重要环节&#xff0c;它主要验证系统不同模块之间的通信和数据交互是否正常。在软件开发过程中&#xff0c;各个模块之间的接口是实现功能的关键要素&#xff0c;因此对接口进行全面而准确的测试是确保系统稳定性和可靠性的关键步骤。 接口测试的核心目…...

C++初阶学习第五弹——类与对象(下)

类与对象&#xff08;上&#xff09;&#xff1a;C初阶学习第三弹——类与对象&#xff08;上&#xff09;-CSDN博客 类和对象&#xff08;中&#xff09;&#xff1a;C初阶学习第四弹——类与对象&#xff08;中&#xff09;-CSDN博客 一.赋值运算符重载 1.1 运算符重载 C为…...

KubeSphere 容器平台高可用:环境搭建与可视化操作指南

Linux_k8s篇 欢迎来到Linux的世界&#xff0c;看笔记好好学多敲多打&#xff0c;每个人都是大神&#xff01; 题目&#xff1a;KubeSphere 容器平台高可用&#xff1a;环境搭建与可视化操作指南 版本号: 1.0,0 作者: 老王要学习 日期: 2025.06.05 适用环境: Ubuntu22 文档说…...

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…...

Golang 面试经典题:map 的 key 可以是什么类型?哪些不可以?

Golang 面试经典题&#xff1a;map 的 key 可以是什么类型&#xff1f;哪些不可以&#xff1f; 在 Golang 的面试中&#xff0c;map 类型的使用是一个常见的考点&#xff0c;其中对 key 类型的合法性 是一道常被提及的基础却很容易被忽视的问题。本文将带你深入理解 Golang 中…...

智慧工地云平台源码,基于微服务架构+Java+Spring Cloud +UniApp +MySql

智慧工地管理云平台系统&#xff0c;智慧工地全套源码&#xff0c;java版智慧工地源码&#xff0c;支持PC端、大屏端、移动端。 智慧工地聚焦建筑行业的市场需求&#xff0c;提供“平台网络终端”的整体解决方案&#xff0c;提供劳务管理、视频管理、智能监测、绿色施工、安全管…...

江苏艾立泰跨国资源接力:废料变黄金的绿色供应链革命

在华东塑料包装行业面临限塑令深度调整的背景下&#xff0c;江苏艾立泰以一场跨国资源接力的创新实践&#xff0c;重新定义了绿色供应链的边界。 跨国回收网络&#xff1a;废料变黄金的全球棋局 艾立泰在欧洲、东南亚建立再生塑料回收点&#xff0c;将海外废弃包装箱通过标准…...

Keil 中设置 STM32 Flash 和 RAM 地址详解

文章目录 Keil 中设置 STM32 Flash 和 RAM 地址详解一、Flash 和 RAM 配置界面(Target 选项卡)1. IROM1(用于配置 Flash)2. IRAM1(用于配置 RAM)二、链接器设置界面(Linker 选项卡)1. 勾选“Use Memory Layout from Target Dialog”2. 查看链接器参数(如果没有勾选上面…...

WEB3全栈开发——面试专业技能点P2智能合约开发(Solidity)

一、Solidity合约开发 下面是 Solidity 合约开发 的概念、代码示例及讲解&#xff0c;适合用作学习或写简历项目背景说明。 &#x1f9e0; 一、概念简介&#xff1a;Solidity 合约开发 Solidity 是一种专门为 以太坊&#xff08;Ethereum&#xff09;平台编写智能合约的高级编…...

蓝桥杯3498 01串的熵

问题描述 对于一个长度为 23333333的 01 串, 如果其信息熵为 11625907.5798&#xff0c; 且 0 出现次数比 1 少, 那么这个 01 串中 0 出现了多少次? #include<iostream> #include<cmath> using namespace std;int n 23333333;int main() {//枚举 0 出现的次数//因…...

搭建DNS域名解析服务器(正向解析资源文件)

正向解析资源文件 1&#xff09;准备工作 服务端及客户端都关闭安全软件 [rootlocalhost ~]# systemctl stop firewalld [rootlocalhost ~]# setenforce 0 2&#xff09;服务端安装软件&#xff1a;bind 1.配置yum源 [rootlocalhost ~]# cat /etc/yum.repos.d/base.repo [Base…...

学习一下用鸿蒙​​DevEco Studio HarmonyOS5实现百度地图

在鸿蒙&#xff08;HarmonyOS5&#xff09;中集成百度地图&#xff0c;可以通过以下步骤和技术方案实现。结合鸿蒙的分布式能力和百度地图的API&#xff0c;可以构建跨设备的定位、导航和地图展示功能。 ​​1. 鸿蒙环境准备​​ ​​开发工具​​&#xff1a;下载安装 ​​De…...