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

Java语法糖详解

前言

        在现代编程语言的发展历程中,语法糖(Syntactic Sugar)作为一种提升代码可读性和开发效率的重要特性,已经成为语言设计的重要组成部分。Java作为一门成熟且广泛应用的编程语言,在其长期演进过程中,语法糖的引入和优化始终是一个重要方向。从Java 5的自动装箱泛型,到Java 8的Lambda表达式,再到后续版本中的模式匹配等特性,语法糖不仅简化了代码编写,还推动了编程范式的革新。

                                        

        然而,语法糖并非仅仅是表面上的语法简化。它的背后隐藏着复杂的编译器处理机制和字节码转换逻辑。同时,语法糖也是大厂 Java 面试常问的一个知识点。本文将从Java编译器的工作机制入手,结合字节码分析与class文件结构解析,深入剖析常见语法糖的实现原理。通过javap反编译工具与ASM字节码框架的实际应用,帮助读者了解语法糖背后的技术本质。



1 什么是语法糖?

语法糖(Syntactic Sugar),也称语法糖衣。是指在编程语言中添加的某种语法,这种语法对语言的功能并没有影响,但是更方便程序员使用,能够让程序更加简洁,有更高的可读性,同时也更容易编写程序。

我们所熟知的编程语言中几乎都有语法糖。比如python中的列表推导式、JavaScript 中的箭头函数、Go 语言中的多返回值、Java 中的 Lambda 表达式等等。

比较有意思的是,在编程领域,除了语法糖,还有语法盐和语法糖精的说法。这里不展开叙述,读者可以自行查阅资料了解。

2 语法糖处理流程解析

2.1 Java编译处理流程

Java源代码(.java)通过javac编译器转换为平台无关的字节码(.class),这个转换过程包含三个关键阶段:

  1. 解析与符号表构建

  2. 语法糖解糖(Desugar)处理

  3. 字节码生成与优化

其中语法糖处理发生在编译器的com.sun.tools.javac.comp.TransTypescom.sun.tools.javac.comp.Lower阶段,负责将高级语法转换为JVM规范定义的标准结构。

2.2 解糖过程示例

以增强for循环为例:

List<String> list = Arrays.asList("a", "b");
for (String s : list) { /*...*/ }

编译器将其转换为:

for (Iterator<String> i = list.iterator(); i.hasNext();) {String s = i.next();/*...*/
}

3 Java中常见的典型语法糖及原理

前面讲过,语法糖的存在主要是方便开发人员使用。但实际上, Java 虚拟机并不支持这些语法糖。这些语法糖在编译阶段就会被还原成简单的基础语法结构,这个过程就是解语法糖

在 Java 语言的编译过程中,我们熟知可使用 `javac` 命令将后缀为 `.java` 的源文件编译成后缀为 `.class` 的字节码文件,这些字节码能够在 Java 虚拟机上运行。深入探究 `com.sun.tools.javac.main.JavaCompiler` 类的源码,可发现其 `compile()` 方法包含多个关键步骤,其中有一个重要环节是调用 `desugar()` 方法。这个方法就是专门负责实现 Java 源文件中语法糖的解糖操作

Java 中最常用的语法糖主要有泛型、变长参数、条件编译、自动拆装箱、内部类等。下面我们一一列举阐述,帮助大家理解这些语法糖背后的原理本质。

1 泛型

        多数语言编程都支持泛型,但是,不同的编译器对于泛型的处理方式是不同的

虽然不同语言编译器对泛型的实现策略存在差异,但是通常可以分为以下两种:

Code Specialization(代码特化)和Code Sharing(代码共享)

        在C++和C#中,泛型的处理采用的是Code Specialization策略,而Java则采纳了Code Sharing的途径。 在Code Sharing模式下,Java编译器为每个泛型类型生成唯一的字节码表示,并将所有泛型类型的实例统一映射到这一字节码上。

        这种映射是通过类型擦除(Type Erasure)技术来实现的,它允许Java虚拟机(JVM)在运行时忽略泛型的具体类型信息。 具体来说,JVM并不能直接识别类似于Map<String, String> map这样的泛型语法。也就是说,对于 Java 虚拟机来说,他根本不认识Map<String, String> map这样的语法。需要在编译阶段通过类型擦除的方式进行解语法糖。

        类型擦除的核心步骤包括:

        ①将所有泛型参数替换为其最左边界类型,即泛型参数的最顶级父类型。

        ②删除代码中的所有类型参数,从而使得泛型类型实例化为原始类型。

举例:

Map<String, String> map = new HashMap<String, String>();
map.put("name", "xiaoliang");
map.put("school", "PKUT");
map.put("address", "anhuihefei");

解语法糖后:

Map map = new HashMap(); // 类型擦除,泛型参数被移除
map.put("name", "xiaoliang"); // 自动装箱,因为 put 方法接受 Object 类型的参数
map.put("school", "PKUT");
map.put("address", "anhuihefei");

又如以下代码:

public static <A extends Comparable<A>> A max(Collection<A> xs) {Iterator<A> xi = xs.iterator();A w = xi.next();while (xi.hasNext()) {A x = xi.next();if (w.compareTo(x) < 0)w = x;}return w;
}

类型擦除后会变成:

 public static Comparable max(Collection xs){Iterator xi = xs.iterator();Comparable w = (Comparable)xi.next();while(xi.hasNext()){Comparable x = (Comparable)xi.next();if(w.compareTo(x) < 0)w = x;}return w;
}

虚拟机中没有泛型,只有普通类和普通方法,所有泛型类的类型参数在编译时都会被擦除,泛型类并没有自己独有的Class类对象。比如并不存在List<String>.class或是List<Integer>.class,而只有List.class

2 变长参数

可变参数(variable arguments)是在 Java 1.5 中引入的一个特性。它允许一个方法把任意数量的值作为参数。

看下以下可变参数代码,其中 print 方法接收可变参数:

public static void main(String[] args) {print("xiaoliang", "博客:https://blog.csdn.net/m0_73804764?spm=1000.2115.3001.5343", "QQ:2337504725");
}public static void print(String... strs) {for (int i = 0; i < strs.length; i++) {System.out.println(strs[i]);}
}

反编译后:

public static void main(String[] args) {String[] varargs = new String[] {"xiaoliang","博客:https://blog.csdn.net/m0_73804764?spm=1000.2115.3001.5343","QQ:2337504725"};print(varargs);
}public static void print(String[] strs) {for (int i = 0; i < strs.length; i++) {String str = strs[i];System.out.println(str);}
}

可变参数在被使用的时候,首先会创建一个数组,数组的长度就是调用该方法是传递的实参的个数,然后再把参数值全部放到这个数组当中,然后再把这个数组作为参数传递到被调用的方法中。

解语法糖原理
①可变参数转换为数组: 当方法 print 被调用时,传入的参数列表 "xiaoliang", "博客:https://blog.csdn.net/m0_73804764?spm=1000.2115.3001.5343", "QQ:2337504725" 会被编译器转换成一个 String 类型的数组。
②方法调用替换: 编译器会将 print 方法的调用替换为对一个新的方法调用的形式,这个新方法接受一个 String 数组作为参数。

3 条件编译

—般情况下,程序中的每一行代码都要参加编译。但有时候出于对程序代码优化的考虑,希望只对其中一部分内容进行编译,此时就需要在程序中加上条件,让编译器只对满足条件的代码进行编译,将不满足条件的代码舍弃,这就是条件编译。

如在 C 或 CPP 中,可以通过预处理语句来实现条件编译。其实在 Java 中也可实现条件编译。我们先来看一段代码:

public class ConditionalCompilation {public static void main(String[] args) {final boolean DEBUG = true;if(DEBUG) {System.out.println("Hello, DEBUG!");}final boolean ONLINE = false;if(ONLINE){System.out.println("Hello, ONLINE!");}}
}

反编译后:

public class ConditionalCompilation
{public ConditionalCompilation(){}public static void main(String args[]){boolean DEBUG = true;System.out.println("Hello, DEBUG!");boolean ONLINE = false;}
}

观察反编译后的代码我们发现,在反编译后的代码中没有System.out.println("Hello, ONLINE!");,这其实就是条件编译。当if(ONLINE)为 false 的时候,编译器就没有对其内的代码进行编译。

所以,Java 语法的条件编译,是通过判断条件为常量的 if 语句实现的。其原理也是 Java 语言的语法糖。根据 if 判断条件的真假,编译器直接把分支为 false 的代码块消除。

解语法糖原理
①常量折叠: 在编译时,编译器会识别出 final 关键字修饰的变量,这些变量被赋值为常量。编译器会执行一个称为“常量折叠”的过程,即它会在编译时计算并替换这些常量的值。
②条件优化: 当编译器遇到条件语句时,如果条件是一个编译时常量(即被 final 修饰且在编译时已知的值),编译器会根据该常量的值来决定是否包含对应的代码块。如果条件为 true,则包含该代码块;如果条件为 false,则不包含该代码块。

4 自动拆装箱

(1)自动装箱:Java 自动将原始类型值转换成对应的对象,比如将 int 的变量转换成 Integer 对象

原始类型 byte, short, char, int, long, float, double 和 boolean

对应的封装类为 Byte, Short, Character, Integer, Long, Float, Double, Boolean。

先来看个自动装箱的代码:

 public static void main(String[] args) {int i = 1688;Integer n = i;
}

反编译后代码如下:

public static void main(String args[])
{int i = 1688;Integer n = Integer.valueOf(i);
}

(2)自动拆箱:当需要将封装类的实例赋值给原始数据类型的变量时,编译器会自动插入对封装类相应 xxxValue 方法的调用,从而提取出原始数据类型的值。比如将 Integer 对象转换成 int 类型值

来看个自动拆箱的代码:

public static void main(String[] args) {Integer i = 1688; // 自动装箱int n = i; // 自动拆箱
}

反编译后:

public static void main(String args[]) {Integer i = Integer.valueOf(1688); // 调用valueOf方法实现装箱int n = i.intValue(); // 调用intValue方法实现拆箱
}

解语法糖原理

总结来说,自动装箱是通过封装类的 valueOf 方法实现的,而自动拆箱则是通过封装类的 xxxValue 方法实现的,其中 xxx 代表对应原始数据类型的名称

5 内部类

内部类又称为嵌套类,可以把内部类理解为外部类的一个普通成员。

内部类之所以也是语法糖,是因为它仅仅是一个编译时的概念,outer.java里面定义了一个内部类inner,一旦编译成功,就会生成两个完全不同的.class文件了,分别是outer.class和outer$inner.class。所以内部类的名字完全可以和它的外部类名字相同。

public class OutterClass {private String userName;public String getUserName() {return userName;}public void setUserName(String userName) {this.userName = userName;}public static void main(String[] args) {}class InnerClass{private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}}
}

以上代码编译后会生成两个 class 文件:OutterClass$InnerClass.class、OutterClass.class 。当我们尝试对OutterClass.class文件进行反编译的时候,命令行会打印以下内容:Parsing OutterClass.class...Parsing inner class OutterClass$InnerClass.class... Generating OutterClass.jad 。他会把两个文件全部进行反编译,然后一起生成一个OutterClass.jad文件。文件内容如下:

public class OutterClass
{class InnerClass{public String getName(){return name;}public void setName(String name){this.name = name;}private String name;final OutterClass this$0;InnerClass(){this.this$0 = OutterClass.this;super();}}public OutterClass(){}public String getUserName(){return userName;}public void setUserName(String userName){this.userName = userName;}public static void main(String args1[]){}private String userName;
}

解语法糖原理

当编译器遇到内部类的定义时,它会执行以下步骤来“解语法糖”:

①生成独立的类文件:编译器会为内部类生成一个独立的 .class 文件。这个文件的命名规则通常是外部类名++内部类名,例如‘𝑂𝑢𝑡𝑡𝑒𝑟𝐶𝑙𝑎𝑠𝑠+内部类名,例如‘OutterClassInnerClass.class`。
②修改成员访问:内部类中对外部类成员的访问会被编译器修改,以便在运行时正确地访问这些成员。这通常涉及到添加额外的方法来访问外部类的私有成员。
③添加外部类引用:编译器会在内部类的构造方法中添加一个额外的参数,这个参数是对外部类实例的引用。这样,内部类就可以访问外部类的成员。

6 Lambda表达式

Lambda 表达式是 Java 8 中引入的一个特性,它提供了一种更简洁的方式来表示只有一个抽象方法的接口(称为函数式接口)的实例。

Lambda 表达式通常由以下三部分组成:

  1. 参数列表:对应于函数式接口中的方法的参数。
  2. 箭头(->):将参数列表与方法体分隔开。
  3. 方法体:可以是表达式或代码块,其结果或返回值将作为 Lambda 表达式的返回值。

例如:

Runnable r = () -> System.out.println("Hello, World!");

解语法糖原理

当编译器遇到 Lambda 表达式时,它会执行以下步骤来“解语法糖”:

  1. 生成匿名内部类:编译器会为 Lambda 表达式生成一个匿名内部类,该类实现了函数式接口。

  2. 实现抽象方法:编译器会在匿名内部类中实现函数式接口的抽象方法。Lambda 表达式的参数列表和方法体将被转换成这个方法的参数和代码。

  3. 处理变量捕获:如果 Lambda 表达式访问了外部作用域的变量,编译器会确保这些变量是有效的。对于局部变量,它们必须是事实上的最终变量(effectively final),即它们在 Lambda 表达式被创建之后不能被修改。

解语法糖后:

Runnable r = new Runnable() {@Overridepublic void run() {System.out.println("Hello, World!");}
};

关于 lambda 表达式,有人可能会有质疑,因为网上有人说他并不是语法糖。其实我想纠正下这个说法。Lambda 表达式不是匿名内部类的语法糖,但是他也是一个语法糖。

总结:Lambda 表达式是一种语法糖,它依赖于 JVM 底层的 invokedynamic 指令和方法句柄等特性来实现

相关文章:

Java语法糖详解

前言 在现代编程语言的发展历程中&#xff0c;语法糖&#xff08;Syntactic Sugar&#xff09;作为一种提升代码可读性和开发效率的重要特性&#xff0c;已经成为语言设计的重要组成部分。Java作为一门成熟且广泛应用的编程语言&#xff0c;在其长期演进过程中&#xff0c;语法…...

567.字符串的排列

目录 一、题目二、思路2.1 解题思路2.2 代码尝试2.3 疑难问题 三、解法四、收获4.1 心得4.2 举一反三 一、题目 二、思路 2.1 解题思路 用两个哈希表比较来判断。s1的哈希表是否与s2相同。在窗口滑动过程中&#xff0c;用哈希表来维护。 2.2 代码尝试 class Solution { pub…...

DB2和mysql关于表和索引是否需要reorg的研究

DB2&#xff1a; DB2有个reorgchk的命令&#xff0c;是从SYSSTAT.TABLES和syscat.indexes这两个系统表中查表和索引的信息&#xff0c;并给出是否需要reorg表和索引的建议。 [db2inst1t3-ucm-ucm-rdb ~]$ db2 reorgchk CURRENT STATISTICS on table DB2ADMIN.ACAGENTTREE Ta…...

【Linux系统编程】:自旋锁,读写锁

文章目录 前言1. POSIX自旋锁1.1.定义自旋锁1.2.初始化1.3. 加锁1.4. 尝试加锁操作1.5. 解锁操作1.6. 销毁操作1.7.示例1.8.优缺点优点缺点 1.9.适用场景 2. 读写锁2.1 读写锁的工作原理2.2 读写模型2.3 常用接口2.3.1 定义锁并初始化2.3.2 申请读锁2.3.3 申请写锁2.3.4 解锁2.…...

位运算及常用技巧

涉及位运算的运算符如下表所示&#xff1a; 位运算的运算律&#xff1a; 负数的位运算 首先&#xff0c;我们要知道&#xff0c;在计算机中&#xff0c;运算是使用的二进制补码&#xff0c;而正数的补码是它本身&#xff0c;负数的补码则是符号位不变&#xff0c;其余按位取反…...

Chrome 浏览器:互联网时代的浏览利器

Chrome 浏览器&#xff1a;互联网时代的浏览利器 引言 在互联网时代&#xff0c;浏览器已经成为我们日常生活中不可或缺的工具。作为全球最受欢迎的浏览器之一&#xff0c;Chrome 浏览器凭借其出色的性能、丰富的扩展程序和简洁的界面&#xff0c;赢得了广大用户的喜爱。本文…...

web-文件上传-CTFHub

前言 在众多的CTF平台当中&#xff0c;作者认为CTFHub对于初学者来说&#xff0c;是入门平台的不二之选。CTFHub通过自己独特的技能树模块&#xff0c;可以帮助初学者来快速入门。具体请看官方介绍&#xff1a;CTFHub。 作者更新了CTFHub系列&#xff0c;希望小伙伴们多多支持…...

【react】react面试题

react面试题 对 React 的理解、特性 react18有哪些更新 JSX是什么 解释为什么浏览器不能读取jsx ReactNative中&#xff0c;如何解决8081端口被占用而提示无法访问的问题&#xff1f; React 生命周期 react事件机制 react 组件传值 React改变state的方式 re…...

逐笔成交逐笔委托Level2高频数据下载和分析:20250206

Level2逐笔成交逐笔委托数据分享下载 通过Level2逐笔成交和逐笔委托这种每一笔的毫秒级别的数据可以分析出很多有用的点&#xff0c;包括主力意图&#xff0c;虚假动作&#xff0c;让任何操作无所遁形。适合交易大师来分析主力规律&#xff0c;也适合人工智能领域的机器学习&a…...

__cvta_generic_to_shared

一 测试代码 #include <cuda_runtime.h> #include <cstdio> #include <cstdint>__global__ void test_cp_async(int* __restrict__ A,int* __restrict__ B){int tid = threadIdx.x;A[tid] = tid;__shared__ int smem[32];size_t smemAddr = __cvta_generic_…...

C++学习——缺省参数、重载函数、引用

目录 前言 一、缺省参数 1.1概念 1.2写法 1.3半缺省 1.4使用 二、重载函数 2.1.概念 2.2类型 2.3参数 2.4顺序 2.5问题 2.6原理 三、引用 1、引用是什么&#xff1f; 2、引用的使用方法 3、引用特性 1、引用在定义的时候必须要初始化 2、一个变量会有多个引用…...

docker-compose 配置nginx

前言 前端打包的dist文件在宿主机&#xff0c;nginx运行在docker-compose 问题 nginx.conf 在本地配置可以生效&#xff0c;但是链接到容器就报错 基于本地的nginx运行&#xff0c;本地nginx.conf 如下 server {listen 8081;location / {root /usr/local/software/testweb/…...

LQB(0)-python-基础知识

一、Python开发环境与基础知识 python解释器&#xff1a;用于解释python代码 方式&#xff1a; 1.直接安装python解释器 2.安装Anaconda管理python环境 python开发环境&#xff1a;用于编写python代码 1.vscode 2.pycharm # 3.安装Anaconda后可以使用网页版的jupyter n…...

【C语言】指针运算与数组关系:详细分析与实例讲解

博客主页&#xff1a; [小ᶻ☡꙳ᵃⁱᵍᶜ꙳] 本文专栏: C语言 文章目录 &#x1f4af;前言&#x1f4af;1. 指针的基础运算1.1 指针的加减运算1.2 指针加整数与指针减整数1.3 指针与指针的运算 &#x1f4af;2. 指针的实际应用&#xff1a;模拟 strlen 函数2.1 使用指针模拟…...

C++数组

指针&#xff0c;是C数组工作方式的基础。 数组&#xff0c;基本上是元素的集合。按特定的顺序排列的一堆东西。 C数组&#xff0c;就是表示一堆的变量组成的集合。一般是一行相同类型的变量。 例子&#xff1a; #include <iostream> int main() {int example[5];exa…...

OSPF基础(2)

一、LSA的头部 LSA是OSPF的一个核心内容&#xff0c;如果没有LSA&#xff0c;OSPF是无法描述网络的拓扑结构及网段信息的,也无法传递路由信息&#xff0c;更加无法正常工作&#xff0c;在OSPFV2中&#xff0c;需要我们掌握的主要有6种。 LSA头部一共20byte&#xff0c;每个字段…...

DeepSeek R1 简单指南:架构、训练、本地部署和硬件要求

DeepSeek 的 LLM 推理新方法 DeepSeek 推出了一种创新方法&#xff0c;通过强化学习 (RL) 来提高大型语言模型 (LLM) 的推理能力&#xff0c;其最新论文 DeepSeek-R1 对此进行了详细介绍。这项研究代表了我们如何通过纯强化学习来增强 LLM 解决复杂问题的能力&#xff0c;而无…...

javaEE-6.网络原理-http

目录 什么是http? http的工作原理&#xff1a; 抓包工具 fiddler的使用 HTTP请求数据: 1.首行:​编辑 2.请求头(header) 3.空行&#xff1a; 4.正文&#xff08;body&#xff09; HTTP响应数据 1.首行&#xff1a;​编辑 2.响应头 3.空行&#xff1a; 4.响应正文…...

把bootstrap5.3.3整合到wordpress主题中的方法

以下是将 Bootstrap 5.3.3 整合到 WordPress 主题中的方法&#xff1a; 下载 Bootstrap 文件&#xff1a;从 Bootstrap 官网下载最新的 5.3.3 版本的 CSS 和 JavaScript 文件。 上传文件到主题目录&#xff1a;将下载的 CSS 文件上传到 WordPress 主题文件夹中的 /css 文件夹…...

深度整理总结MySQL——Buffer Pool工作原理

Buffer Pool工作原理 前言为什么会有Buffer PoolBuffer Pool介绍Buffer Pool有多大Buffer Pool缓存什么呢Buffer Pool碎片空间查询一条记录&#xff0c;就只需要缓冲一条记录吗 如何管理Buffer Pool如何管理空闲页如何管理脏页如何提高缓存命中率 LRU带来的问题预读失效Buffer …...

langchain教程-9.Retriever/检索器

前言 该系列教程的代码: https://github.com/shar-pen/Langchain-MiniTutorial 我主要参考 langchain 官方教程, 有选择性的记录了一下学习内容 这是教程清单 1.初试langchain2.prompt3.OutputParser/输出解析4.model/vllm模型部署和langchain调用5.DocumentLoader/多种文档…...

凝思60重置密码

凝思系统重置密码 - 赛博狗尾草 - 博客园 问题描述 凝思系统进入单用户模式&#xff0c;在此模式下&#xff0c;用户可以访问修复错误配置的文件。也可以在此模式下安装显卡驱动&#xff0c;解决和已加载驱动的冲突问题。 适用范围 linx-6.0.60 linx-6.0.80 linx-6.0.100…...

指针基础知识1

1.内存和地址 1.案例 我们可以借助一个生活在的案例来熟悉电脑中内存和地址的关系&#xff1a; 假设有⼀栋宿舍楼&#xff0c;把你放在楼里&#xff0c;楼上有100个房间&#xff0c;但是房间没有编号&#xff0c;你的⼀个朋友来找你玩&#xff0c; 如果想找到你&#xff0c;…...

大数据学习之Spark分布式计算框架RDD、内核进阶

一.RDD 28.RDD_为什么需要RDD 29.RDD_定义 30.RDD_五大特性总述 31.RDD_五大特性1 32.RDD_五大特性2 33.RDD_五大特性3 34.RDD_五大特性4 35.RDD_五大特性5 36.RDD_五大特性总结 37.RDD_创建概述 38.RDD_并行化创建 演示代码&#xff1a; // 获取当前 RDD 的分区数 Since ( …...

Windows本地部署DeepSeek-R1大模型并使用web界面远程交互

文章目录 前言1. 安装Ollama2. 安装DeepSeek-r1模型3. 安装图形化界面3.1 Windows系统安装Docker3.2 Docker部署Open WebUI3.3 添加Deepseek模型 4. 安装内网穿透工具5. 配置固定公网地址 前言 最近爆火的国产AI大模型Deepseek详细大家都不陌生&#xff0c;不过除了在手机上安…...

【Linux系统】线程:线程控制

一、POSIX线程库 与线程有关的函数构成了一个完整的系列&#xff0c;绝大多数函数的名字都是以“pthread_”打头的。使用这些函数库&#xff0c;要通过引入头文件 <pthread.h>。链接这些线程函数库时要使用编译器命令的 -lpthread 选项。 二、轻量级进程创建&#xff1a…...

GoFrame 微服务开发指南

基本介绍 GoFrame 框架支持微服务模式开发&#xff0c;提供了常用的微服务组件、开发工具、开发教程帮助团队快速微服务转型。 微服务组件简介 GoFrame 微服务组件具有低耦合及通用化设计&#xff0c;组件化使用支持大部分的微服务通信协议。在官方文档中&#xff0c;主要以…...

Python-基于PyQt5,Pillow,pathilb,imageio,moviepy,sys的GIF(动图)制作工具(进阶版)

前言&#xff1a;在抖音&#xff0c;快手等社交平台上&#xff0c;我们常常见到各种各样的GIF动画。在各大评论区里面&#xff0c;GIF图片以其短小精悍、生动有趣的特点&#xff0c;被广泛用于分享各种有趣的场景、搞笑的瞬间、精彩的动作等&#xff0c;能够快速吸引我们的注意…...

PhpStorm下载、安装、配置教程

前面的文章中&#xff0c;都是把.php文件放在WampServer的www目录下&#xff0c;通过浏览器访问运行。这篇文章就简单介绍一下PhpStorm这个php集成开发工具的使用。 目录 下载PhpStorm 安装PhpStorm 配置PhpStorm 修改个性化设置 修改字符编码 配置php的安装路径 使用Ph…...

春节假期旅游热潮下,景区医疗安全如何全面升级?

春节假期旅游热潮下&#xff0c;景区医疗安全如何全面升级&#xff1f; 随着旅游业的不断繁荣&#xff0c;春节假期期间&#xff0c;各大景区再次迎来了游客的高峰期。面对如此庞大的客流量&#xff0c;景区不仅要在服务接待上下功夫&#xff0c;更要将医疗安全保障工作提升到…...

惠普HP工作站如何关闭关闭RAID?

惠普HP工作站如何关闭关闭RAID&#xff1f; 前言进入BIOS进入“先进”选项卡&#xff0c;点击“系统选项”。取消勾选“sSATA控制器RAID模式”&#xff0c;按下F10保存重启。 前言 惠普工作站默认启用了RAID模式&#xff0c;导致许多PE工具无法识别RAID模式下的硬盘。可以通过…...

ESP-Skainet智能语音助手,ESP32-S3物联网方案,设备高效语音交互

在科技飞速发展的今天&#xff0c;智能语音助手正逐渐渗透到我们生活的方方面面&#xff0c;而智能语音助手凭借其卓越的技术优势&#xff0c;成为了智能生活领域的一颗璀璨明星。 ESP-Skainet智能语音助手的强大之处在于其支持唤醒词引擎&#xff08;WakeNet&#xff09;、离…...

mac下生成.icns图标

笔记原因&#xff1a; 今日需要在mac下开发涉及图标文件的使用及icons文件的生成&#xff0c;所以记录一下。 网络上都是一堆命令行需要打印太麻烦了&#xff0c;写一个一键脚本。 步骤一 将需要生成的png格式文件重命名为“pic.png” mv xxxx.png pic.png 步骤二 下载我…...

【MySQL】centos 7 忘记数据库密码

vim /etc/my.cnf文件&#xff1b; 在[mysqld]后添加skip-grant-tables&#xff08;登录时跳过权限检查&#xff09; 重启MySQL服务&#xff1a;sudo systemctl restart mysqld 登录mysql&#xff0c;输入mysql –uroot –p&#xff1b;直接回车&#xff08;Enter&#xff09; 输…...

【kafka的零拷贝原理】

kafka的零拷贝原理 一、零拷贝技术概述二、Kafka中的零拷贝原理三、零拷贝技术的优势四、零拷贝技术的实现细节五、注意事项一、零拷贝技术概述 零拷贝(Zero-Copy)是一种减少数据拷贝次数,提高数据传输效率的技术。 在传统的数据传输过程中,数据需要在用户态和内核态之间…...

【JavaEE】Spring Web MVC

目录 一、Spring Web MVC简介 1.1 MVC简介1.2 Spring MVC1.3 RequestMapping注解1.3.1 使用1.3.2 RequestMapping的请求设置 1.3.2.1 方法11.3.2.2 方法2 二、Postman介绍 2.1 创建请求2.2 界面如下&#xff1a;2.3 传参介绍 一、Spring Web MVC简介 官方文档介绍&#xff…...

《解锁GANs黑科技:打造影视游戏的逼真3D模型》

在游戏与影视制作领域&#xff0c;逼真的3D模型是构建沉浸式虚拟世界的关键要素。从游戏中栩栩如生的角色形象&#xff0c;到影视里震撼人心的宏大场景&#xff0c;高品质3D模型的重要性不言而喻。随着人工智能技术的飞速发展&#xff0c;生成对抗网络&#xff08;GANs&#xf…...

【大数据技术】词频统计样例(hadoop+mapreduce+yarn)

词频统计(hadoop+mapreduce+yarn) 搭建完全分布式高可用大数据集群(VMware+CentOS+FinalShell) 搭建完全分布式高可用大数据集群(Hadoop+MapReduce+Yarn) 在阅读本文前,请确保已经阅读过以上两篇文章,成功搭建了Hadoop+MapReduce+Yarn的大数据集群环境。 写在前面 Wo…...

deepseek与openai关系

‌DeepSeek与OpenAI之间的关系主要体现在技术竞争和合作的可能性上。‌ 首先&#xff0c;DeepSeek是由中国的深度求索公司开发的&#xff0c;成立于2023年&#xff0c;专注于人工智能技术研发。其大模型DeepSeek-R1在数学、代码、自然语言推理等任务上的性能能够比肩OpenAI的G…...

51页精品PPT | 数据中台与数据治理服务及案例

案例的核心内容围绕数据中台与数据治理服务展开&#xff0c;详细介绍了数据治理的整体方法论、数据中台的建设路径以及如何通过数据治理和数据中台提升业务效率和数据质量。本案例强调了数据治理的重要性&#xff0c;包括数据标准、数据质量、数据安全等方面的管理&#xff0c;…...

使用 cipher /w 清除磁盘删除残留数据(Windows) - 随笔

cipher命令是Windows 系统自带的一个用于管理文件加密和磁盘数据清除的工具。通过 cipher /w 命令&#xff0c;可以清除磁盘上已删除文件的残留数据&#xff0c;确保这些数据无法被恢复。以下是一个简易的批处理脚本&#xff0c;用于清除指定磁盘上的加密数据。 echo off :: 清…...

RuntimeWarning: invalid value encountered in sqrt

代码出处&#xff1a; GitHub - wangsen1312/joints2smpl: fit smpl parameters model using 3D joints RuntimeWarning: invalid value encountered in sqrt 你可以通过以下几种方式解决这个问题&#xff1a; 1. 检查负值或零行列式 确保协方差矩阵是正半定的&#xff0c;这…...

3步打造C# API安全密盾

引言&#xff1a;API 安全的重要性 在数字化浪潮中&#xff0c;应用程序编程接口&#xff08;API&#xff09;已成为不同软件系统之间通信和数据交互的关键桥梁。无论是企业内部的微服务架构&#xff0c;还是面向外部用户的在线服务&#xff0c;API 都承担着数据传输和业务逻辑…...

项目实操:windows批处理拉取git库和处理目录、文件

初级代码游戏的专栏介绍与文章目录-CSDN博客 我的github&#xff1a;codetoys&#xff0c;所有代码都将会位于ctfc库中。已经放入库中我会指出在库中的位置。 这些代码大部分以Linux为目标但部分代码是纯C的&#xff0c;可以在任何平台上使用。 源码指引&#xff1a;github源…...

接入 deepseek 实现AI智能问诊

1. 准备工作 注册 DeepSeek 账号 前往 DeepSeek 官网 注册账号并获取 API Key。 创建 UniApp 项目 使用 HBuilderX 创建一个新的 UniApp 项目&#xff08;选择 Vue3 或 Vue2 模板&#xff09;。 安装依赖 如果需要在 UniApp 中使用 HTTP 请求&#xff0c;推荐使用 uni.requ…...

ubuntu22.04源码编译mysql8.0.X详细流程【由deepseek提供】

以下是在 Ubuntu 22.04 上从源代码编译安装 MySQL 8.0.X&#xff08;以 MySQL 8.0.37 为例&#xff09;的详细操作流程&#xff1a; 一、准备工作 1. 更新系统 sudo apt update && sudo apt upgrade -y sudo apt install -y build-essential cmake pkg-config libssl…...

富唯智能复合机器人拓展工业新维度

富唯智能复合机器人是富唯智能倾力打造的一款集高度自动化、智能化和多功能性于一体的机器人。它融合了机械、电子、计算机、传感器等多个领域的前沿技术&#xff0c;通过精密的算法和控制系统&#xff0c;实现了对复杂生产环境的快速适应和高效作业。 富唯智能复合机器人的特点…...

【2】高并发导出场景下,服务器性能瓶颈优化方案-异步导出

Java 异步导出是一种在处理大量数据或复杂任务时优化性能和用户体验的重要技术。 1. 异步导出的优势 异步导出是指将导出操作从主线程中分离出来&#xff0c;通过后台线程或异步任务完成数据处理和文件生成。这种方式可以显著减少用户等待时间&#xff0c;避免系统阻塞&#x…...

verdi 查看覆盖率

点击Tools -> Coverage&#xff0c;会出现一个Verdi:vdCoverage:1页面点击File->Open/Add Database, 会出现一个 Open/Add Coverage Database页面&#xff0c; 在Design Hierarchy/Testbench Location 中输入 vdb路径点击… &#xff0c; 会出现当前路径下的文件&#xf…...

【React】路由处理的常见坑与解决方法,React Router 的动态路由与懒加载问题

在使用 React Router 时,动态路由和懒加载是非常常见的需求,但也可能会遇到一些坑。以下是常见问题以及对应的解决方法。 一、React Router 动态路由常见问题 1. 动态路由匹配问题 动态路由通常通过 :param 定义路径参数,但如果路径参数与静态路由有重叠,可能会导致匹配问…...