深入源码P3C-PMD:rule (4)

系列文章目录

文章目录

  • 系列文章目录
  • rule 的应用
    • 类别 rule
  • rule 自定义
    • XML rule 定义
    • Tree 漫游
    • 错误报告
    • 生命周期
  • designer

rule相关的代码在每个子 module 的 rule 文件夹。而且也以一些 ruleset 为范围分了文件夹,如下图所示:

在这里插入图片描述
对每个 rule 来说,定义检测规则并抛出错误,报错方法:addViolation

在这里插入图片描述
对应的 rule 相关 message 在 xml 中定义:
 在这里插入图片描述
这里和 spotbugs 是一个思路,message 做 rule 代码与 xml 隔离,配置大于编码。rule 使用引擎调用,并利用 visitor 模式做行为与数据的解耦。整体思路是一脉相承的。


rule 的应用

首先,遍历规则集合rules中的每个规则rule。

  • 检查当前语言版本的规则是否适用于当前的索引。如果不符合,则跳过该规则,不尝试应用它。
  • 创建一个RuleContext对象ctx,用于存储规则应用时的上下文信息。
  • 调用规则的start方法,开始应用规则。
  • 使用TimedOperation对象rcto记录规则应用的时间。
  • 获取规则的目标选择器的访问节点。
  • 遍历目标选择器的访问节点,对每个节点应用规则。
  • 记录应用规则的节点数量。
  • 在应用规则的过程中,捕获并处理可能的运行时异常和栈溢出异常。
  • 在应用规则之后,关闭规则应用的时间记录。
  • 调用规则的end方法,表示规则应用完成。
private void applyOnIndex(TreeIndex idx, Collection<? extends Rule> rules, FileAnalysisListener listener) {for (Rule rule : rules) {if (!RuleSet.applies(rule, currentLangVer)) {continue; // No point in even trying to apply the rule}RuleContext ctx = RuleContext.create(listener, rule);rule.start(ctx);try (TimedOperation rcto = TimeTracker.startOperation(TimedOperationCategory.RULE, rule.getName())) {int nodeCounter = 0;Iterator<? extends Node> targets = rule.getTargetSelector().getVisitedNodes(idx);while (targets.hasNext()) {Node node = targets.next();try {nodeCounter++;rule.apply(node, ctx);} catch (RuntimeException e) {reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), true);} catch (StackOverflowError e) {reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());} catch (AssertionError e) {reportOrRethrow(listener, rule, node, AssertionUtil.contexted(e), SystemProps.isErrorRecoveryMode());}}rcto.close(nodeCounter);} finally {rule.end(ctx);}}}

类别 rule

和 spotbugs 的能到某些行等的不同,AST 的建立是以元数据为中心,
visit 的类型有如下这些,共 122 个类别:

 public default R visitJavaNode(JavaNode node, P data) { return visitNode(node, data); }default R visit(ASTCompilationUnit node, P data) { return visitJavaNode(node, data); }default R visit(ASTPackageDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTImportDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTModifierList node, P data) { return visitJavaNode(node, data); }default R visit(ASTClassOrInterfaceDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTExtendsList node, P data) { return visitJavaNode(node, data); }default R visit(ASTImplementsList node, P data) { return visitJavaNode(node, data); }default R visit(ASTPermitsList node, P data) { return visitJavaNode(node, data); }default R visit(ASTEnumDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTEnumBody node, P data) { return visitJavaNode(node, data); }default R visit(ASTEnumConstant node, P data) { return visitJavaNode(node, data); }default R visit(ASTRecordDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTRecordComponentList node, P data) { return visitJavaNode(node, data); }default R visit(ASTRecordComponent node, P data) { return visitJavaNode(node, data); }default R visit(ASTRecordBody node, P data) { return visitJavaNode(node, data); }default R visit(ASTCompactConstructorDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTTypeParameters node, P data) { return visitJavaNode(node, data); }default R visit(ASTTypeParameter node, P data) { return visitJavaNode(node, data); }default R visit(ASTClassOrInterfaceBody node, P data) { return visitJavaNode(node, data); }default R visit(ASTEmptyDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTFieldDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTVariableDeclarator node, P data) { return visitJavaNode(node, data); }default R visit(ASTVariableDeclaratorId node, P data) { return visitJavaNode(node, data); }default R visit(ASTReceiverParameter node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayInitializer node, P data) { return visitJavaNode(node, data); }default R visit(ASTMethodDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTFormalParameters node, P data) { return visitJavaNode(node, data); }default R visit(ASTFormalParameter node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayType node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayDimensions node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayTypeDim node, P data) { return visitJavaNode(node, data); }default R visit(ASTConstructorDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTBlock node, P data) { return visitJavaNode(node, data); }default R visit(ASTExplicitConstructorInvocation node, P data) { return visitJavaNode(node, data); }default R visit(ASTInitializer node, P data) { return visitJavaNode(node, data); }default R visit(ASTIntersectionType node, P data) { return visitJavaNode(node, data); }default R visit(ASTClassOrInterfaceType node, P data) { return visitJavaNode(node, data); }default R visit(ASTTypeArguments node, P data) { return visitJavaNode(node, data); }default R visit(ASTWildcardType node, P data) { return visitJavaNode(node, data); }default R visit(ASTPrimitiveType node, P data) { return visitJavaNode(node, data); }default R visit(ASTVoidType node, P data) { return visitJavaNode(node, data); }default R visit(ASTThrowsList node, P data) { return visitJavaNode(node, data); }default R visit(ASTAssignmentExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTConditionalExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTInfixExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTTypePattern node, P data) { return visitJavaNode(node, data); }default R visit(ASTRecordPattern node, P data) { return visitJavaNode(node, data); }default R visit(ASTComponentPatternList node, P data) { return visitJavaNode(node, data); }default R visit(ASTUnaryExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTCastExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTThisExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTSuperExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTClassLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTMethodCall node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayAccess node, P data) { return visitJavaNode(node, data); }default R visit(ASTFieldAccess node, P data) { return visitJavaNode(node, data); }default R visit(ASTMethodReference node, P data) { return visitJavaNode(node, data); }default R visit(ASTLambdaExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTLambdaParameterList node, P data) { return visitJavaNode(node, data); }default R visit(ASTLambdaParameter node, P data) { return visitJavaNode(node, data); }default R visit(ASTBooleanLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTNullLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTNumericLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTCharLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTStringLiteral node, P data) { return visitJavaNode(node, data); }default R visit(ASTArgumentList node, P data) { return visitJavaNode(node, data); }default R visit(ASTConstructorCall node, P data) { return visitJavaNode(node, data); }default R visit(ASTAnonymousClassDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayAllocation node, P data) { return visitJavaNode(node, data); }default R visit(ASTArrayDimExpr node, P data) { return visitJavaNode(node, data); }default R visit(ASTExpressionStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTLabeledStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTLocalVariableDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTEmptyStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchArrowBranch node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchFallthroughBranch node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchLabel node, P data) { return visitJavaNode(node, data); }default R visit(ASTSwitchGuard node, P data) { return visitJavaNode(node, data); }default R visit(ASTYieldStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTIfStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTWhileStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTDoStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTForeachStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTForStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTForInit node, P data) { return visitJavaNode(node, data); }default R visit(ASTStatementExpressionList node, P data) { return visitJavaNode(node, data); }default R visit(ASTForUpdate node, P data) { return visitJavaNode(node, data); }default R visit(ASTBreakStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTContinueStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTReturnStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTThrowStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTSynchronizedStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTTryStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTResourceList node, P data) { return visitJavaNode(node, data); }default R visit(ASTResource node, P data) { return visitJavaNode(node, data); }default R visit(ASTCatchClause node, P data) { return visitJavaNode(node, data); }default R visit(ASTCatchParameter node, P data) { return visitJavaNode(node, data); }default R visit(ASTUnionType node, P data) { return visitJavaNode(node, data); }default R visit(ASTFinallyClause node, P data) { return visitJavaNode(node, data); }default R visit(ASTAssertStatement node, P data) { return visitJavaNode(node, data); }default R visit(ASTAnnotation node, P data) { return visitJavaNode(node, data); }default R visit(ASTAnnotationMemberList node, P data) { return visitJavaNode(node, data); }default R visit(ASTMemberValuePair node, P data) { return visitJavaNode(node, data); }default R visit(ASTMemberValueArrayInitializer node, P data) { return visitJavaNode(node, data); }default R visit(ASTAnnotationTypeDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTAnnotationTypeBody node, P data) { return visitJavaNode(node, data); }default R visit(ASTDefaultValue node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleDeclaration node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleRequiresDirective node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleExportsDirective node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleOpensDirective node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleUsesDirective node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleProvidesDirective node, P data) { return visitJavaNode(node, data); }default R visit(ASTModuleName node, P data) { return visitJavaNode(node, data); }default R visit(ASTAmbiguousName node, P data) { return visitJavaNode(node, data); }default R visit(ASTVariableAccess node, P data) { return visitJavaNode(node, data); }default R visit(ASTTypeExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTPatternExpression node, P data) { return visitJavaNode(node, data); }default R visit(ASTLocalClassStatement node, P data) { return visitJavaNode(node, data); }

rule 自定义

PMD 是基于 AST的检测框架,语法树表示了源代码中的语法与语义特征。 Rule 遍历 AST 并匹配某些条件。
在这里插入图片描述
自定义规则有2种方式: Xpath query 和 Java visitor。 Xpath 直接使用 XML 定义 更简单,但是有一些只能通过 Java 调用 PMD api 的实现,是Xpath无法达到的。

XML rule 定义

新的规则必须在 ruleset 中定义,并使用 class 属性,引用规则的实现。

java rule:
<rule name="MyJavaRule"language="java"message="Violation!"class="com.me.MyJavaRule"><description>Description</description><priority>3</priority>
</rule>
xpath:
<rule name="MyXPathRule"language="java"message="Violation!"class="net.sourceforge.pmd.lang.rule.xpath.XPathRule"><description>Description</description><priority>3</priority><properties><property name="xpath"><value><![CDATA[
//ClassOrInterfaceDeclaration
]]></value></property></properties>
</rule>

要写 Java rule,需要完成如下

  1. 编写一个实现接口Rule的Java类。每种语言实现都提供了一个基本规则类来缓解您的痛苦,例如AbstractJavaRule。
  2. 编译此类,将其链接到PMD API(例如,使用PMD作为Maven依赖项)
  3. 将其打包到JAR中,并将其添加到PMD的执行类路径中
  4. 在规则集XML中声明规则

Tree 漫游

开始应用 rule 的时候,会遍历整棵树来寻找错误,每个 rule 都定义了一个特别的 visit 方法。可以根据需要在 visitor 中选择需要的节点 override 该方法。

public class MyRule extends AbstractJavaRule {@Overridepublic Object visit(ASTVariableId node, Object data) {// This method is called on each node of type ASTVariableId// in the ASTif (node.getType() == short.class) {// reports a violation at the position of the node// the "data" parameter is a context object handed to by your rule// the message for the violation is the message defined in the rule declaration XML elementasCtx(data).addViolation(node);}// this calls back to the default implementation, which recurses further down the subtreereturn super.visit(node, data);}
}

super.visit(node, data) 调用在规则实现中非常常见,因为它通过访问当前节点的所有子代来继续遍历。如果不需要再往子节点遍历,可以不用再调用 super 的方法。

一个加速手段是使用 rulechain。条件是 rule 不需要维护 visit 之间的状态,这类规则也很常见:
在这里插入图片描述
在这里插入图片描述
rulechain 不会递归整棵树,而是只遍历它关心的部分

  • 必须 override buildTargetSelector 方法,工程方法 forType 能用例创建这样的选择器。
  • 继承 AbstractJavaRulechainRule. 调用父类的构造器,并提供所需要的类型
  • visit 方法不能递归,不能调用 super.visit

在这里插入图片描述
在这里插入图片描述
PMD 提供了2中 AST 导航的方式:NodeStream 和 Node api:

ancestors
ancestorsOrSelf
children
descendants
descendantsOrSelf
ancestors
children
descendants

NodeStream.of(someNode)                           // the stream here is empty if the node is null.filterIs(ASTVariableDeclaratorId.class)// the stream here is empty if the node was not a variable declarator id.followingSiblings()                    // the stream here contains only the siblings, not the original node.filterIs(ASTVariableInitializer.class).children(ASTExpression.class).children(ASTPrimaryExpression.class).children(ASTPrimaryPrefix.class).children(ASTLiteral.class).filterMatching(Node::getImage, "0").filterNot(ASTLiteral::isStringLiteral).nonEmpty(); // If the stream is non empty here, then all the pipeline matched

Node api:
getParent
getNumChildren
getChild
getFirstChild
getLastChild
getPreviousSibling
getNextSibling
firstChild

错误报告

addViolation
addViolationWithMessage 这个方法不会使用 xml 中定义的 message。

生命周期

对于每个线程,规则都深拷贝一份,而且每个线程分析的不同的文件集。一个rule 的生命周期,比较简单:

  • start 调用依次,parsing 之前
  • apply 调用 visit 方法
  • end 结束文件处理

designer

若缺少 javafx 框架,下载地址: https://openjfx.cn/dl/
并在环境变量里配置 JAVAFX_HOME
在这里插入图片描述
使用命令调用:

pmd.bat designer

在这里插入图片描述
双击代码行,定位到导航树:
在这里插入图片描述
GUI 相关的比较简单,大家可以自行探索。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/392846.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

PHP教育培训小程序系统源码

&#x1f680;【学习新纪元】解锁教育培训小程序的无限可能✨ &#x1f4da; 引言&#xff1a;教育培训新风尚&#xff0c;小程序来引领&#xff01; Hey小伙伴们&#xff0c;是不是还在为找不到合适的学习资源而烦恼&#xff1f;或是厌倦了传统教育模式的单调&#xff1f;今…

盘点12款企业常用源代码加密软件,源代码防泄密很重要!

在当今的商业环境中&#xff0c;源代码作为企业的核心资产之一&#xff0c;其安全性不容忽视。源代码的泄露可能导致企业丧失竞争优势、面临法律诉讼甚至经济损失。因此&#xff0c;选择合适的源代码加密软件成为企业保护知识产权和核心技术的关键步骤。 1. 安秉源代码加密软件…

【JVM】Java内存区域图文详解

1.JVM运行时区域总览 Java 虚拟机在执行 Java 程序的过程中会把它管理的内存划分成若干个不同的数据区域。 JVM运行时区域也成为Java内存区域。 在讨论Java内存模型时&#xff0c;通常将其分为线程共享区域和线程私有区域&#xff1a; 2.线程私有区域 2.1.程序计数器 程序计…

详解贪心算法

贪心算法&#xff08;Greedy Algorithm) 概述&#xff1a; 贪心算法是一种在求解最优化问题时采取的一种常用算法策略。贪心算法的基本思想是&#xff0c;每次选择当前情况下的局部最优解&#xff0c;并相信这个局部最优解能够导致全局最优解。贪心算法通过迭代的方式一步步地…

SpringBoot3里的文件上传

需求分析&#xff1a; 在用户更换头像或者添加文章时&#xff0c;都需要携带一个图片的URL访问地址。当用户访问文件上传接口将图片的数据上传成功后&#xff0c;服务器会返回一个地址。我们后台需要提供一个文件上传的接口&#xff0c;用来接收前端提交的文件的数据并且返回文…

七夕情人节礼物有哪些走心礼物推荐,盘点惊喜爆棚的四大礼物分享

随着浪漫的七夕情人节的临近&#xff0c;恋人们开始寻找那些能够传达他们挚爱与深情的独特礼物&#xff0c;一份有心的礼物不仅能够成为情感的使者&#xff0c;还能在这一天为爱情增添更多甜蜜与回忆&#xff0c;在这个充满传说与浪漫的节日里&#xff0c;我们精心挑选了一系列…

查询表信息时有一个数据为null相关解决

查询的时候varchar类型的username一直查不到为null,这个问题干了我好久 当时我以为是连接mysql数据库的时候没有在url后面添加添加指定字符的编码、解码格式的参数约束.然后经过分析发现 我创建的这个Account对象 直接上结果&#xff0c;问题出在了setUsername()方法上 错误…

Scrapy入门篇

免责声明 本文的爬虫知识仅用于合法和合理的数据收集&#xff0c;使用者需遵守相关法律法规及目标网站的爬取规则&#xff0c;尊重数据隐私&#xff0c;合理设置访问频率&#xff0c;不得用于非法目的或侵犯他人权益。因使用网络爬虫产生的任何法律纠纷或损失&#xff0c;由使用…

用Java手写jvm之模拟方法调用指令invokexxx和方法返回指令xreturn

写在前面 源码 。 本文一起看下方法调用相关的指令invokexxx以及方法返回&#xff08;栈帧弹出线程栈&#xff09;相关的指令xReturn 。 1&#xff1a;正文 因为invokexxx指令和普通的指令不同&#xff0c;会创建一个新的栈帧&#xff0c;并压倒操作数栈中&#xff0c;所以我…

【python】Python中实现定时任务常见的几种方式原理分析与应用实战

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

【OpenCV C++20 学习笔记】腐蚀和膨胀

腐蚀和膨胀 形态学原理膨胀腐蚀 代码实现膨胀函数腐蚀函数运行结果 形态学原理 腐蚀和膨胀通常有以下用途&#xff1a; 去除噪音分离或合并图像中的元素找出图片上的强度的极大值区域和极小值区域 以下图作为原始图片&#xff1a; 膨胀 用核 B B B来扫描图像 A A A&#xff…

VBA学习(22):动态显示日历

这是在ozgrid.com论坛上看到的一个贴子&#xff0c;很有意思&#xff0c;本来使用公式是可以很方便在工作表中实现日历显示的&#xff0c;但提问者因其需要&#xff0c;想使用VBA实现动态显示日历&#xff0c;即根据输入的年份和月份在工作表中显示日历。 下面是实现该效果的VB…

喜报!DAP-seq文章6连发,总IF 95.2

2024年4月29日&#xff0c;河北农业大学林学院李保国山区产业开发与林果产业创新团队与园艺学院田义教授团队联合西北农林科技大学马锋旺教授团队及沈阳农业大学马跃教授团队在Plant Biotechnology Journal&#xff08;影响因子10.1&#xff09;上发表了题为“The MdVQ37-MdWRK…

2024最新版Python基础入门学习路线

Python基础入门学习路线可以概括为以下几个阶段&#xff0c;每个阶段都包含了关键的学习内容和目标&#xff1a; 一、Python语言基础 1. 初识Python语言 Python语言概述&#xff1a;了解Python的起源、特点、应用领域以及发展趋势。环境安装&#xff1a;学习如何在不同的操作系…

18987 随机数(测验)

这个问题可以通过使用集合&#xff08;set&#xff09;和排序来解决。集合是一种数据结构&#xff0c;它可以自动去除重复的元素。然后我们可以将集合中的元素转移到一个数组中&#xff0c;并对&#xfffd;&#xfffd;组进行排序。 以下是使用C的代码实现&#xff1a; #i…

浅谈哈希与哈希表(c++)

目录 一、哈希的基本概念&#xff08;一&#xff09;哈希函数的特性&#xff08;二&#xff09;哈希冲突 二、C 中的哈希表实现三、哈希表的性能分析四、哈希表的应用场景五、优化哈希表的策略六、例题讲解【模板】字符串哈希题目描述输入格式输出格式样例 #1样例输入 #1样例输…

工业5G路由器赋能户外组网远程监控及预警

随着物联网、大数据、云计算等技术的快速发展&#xff0c;工业领域对于远程监控、实时预警和数据传输的需求日益增长。特别是在户外复杂环境下&#xff0c;传统的有线网络组网方式面临着布线难度大、成本高、维护困难等问题。 工业5G路由器在户外组网远程监控预警应用基于高速…

Android开发之事件分发

#来自ウルトラマンゼロ&#xff08;哉阿斯&#xff09; 1 Activity 构成 平常布局展示在ContentView中。 2 事件分发 事件分发的本质其实就是把事件&#xff08;Touch&#xff09;封装成 MotionEvent 类&#xff0c;然后传递给 View 的层级处理。 MotionEvent 事件类型主要有…

RAG与Fine Tuning:如何选择正确的方法

今日份知识你摄入了么&#xff1f; 生成式人工智能有潜力改变你的业务和数据工程团队&#xff0c;但前提是要正确实施。那么&#xff0c;你的数据团队如何才能真正利用大型语言模型或生成式人工智能_&#xff08;GenAI&#xff09;_计划来驱动价值呢&#xff1f; 领先的组织通…

我在高职教STM32——I2C通信入门(1)

大家好,我是老耿,高职青椒一枚,一直从事单片机、嵌入式、物联网等课程的教学。对于高职的学生层次,同行应该都懂的,老师在课堂上教学几乎是没什么成就感的。正是如此,才有了借助CSDN平台寻求认同感和成就感的想法。在这里,我准备陆续把自己花了很多心思设计的教学课件分…