【springboot】RestTemplate序列化RedisSerializer到底该选哪个

news2024/12/24 8:15:41

RedisTemplate是Spring Data Redis提供给用户的最高级的抽象客户端,用户可直接通过RedisTemplate对Redis进行多种操作。

在项目中使用需要引入如下依赖:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>

因为redis是以key-value的形式将数据存在内存中,key就是简单的string,key似乎没有长度限制,不过原则上应该尽可能的短小且可读性强,无论是否基于持久存储,key在服务的整个生命周期中都会在内存中,因此减小key的尺寸可以有效的节约内存,同时也能优化key检索的效率。

value在redis中,存储层面仍然基于string,在逻辑层面,可以是string/set/list/map,不过redis为了性能考虑,使用不同的“encoding”数据结构类型来表示它们。(例如:linkedlist,ziplist等)。

所以可以理解为,其实redis在存储数据时,都把数据转化成了byte[]数组的形式,那么在存取数据时,需要将数据格式进行转化,那么就要用到序列化和反序列化了,这也就是为什么需要配置Serializer的原因。

尽管Redis本身支持多种数据类型,但是Redis底层还是使用二进制存储数据,所以我们需要在应用层对数据的格式进行转换,这种转换称之为序列化。

针对二进制数据的“序列化/反序列化”,Spring提供了一个顶层接口RedisSerializer,并提供了多种实现可供选择(RedisSerializer),如下所示:


下面四个是Spring自带的:

  • StringRedisSerializer
  • JdkSerializationRedisSerializer
  • Jackson2JsonRedisSerializer
  • GenericJackson2JsonRedisSerializer
  • Jackson2JsonRedisSerializer

如果项目中引入了fastjson:

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>${fastjson.version}</version>
</dependency>

还会看到下面2个fastjson的实现类:

  • FastJsonRedisSerializer
  • GenericFastJsonRedisSerializer

StringRedisSerializer

StringRedisSerializer的使用如下:

package com.morris.spring.boot.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.serializer.StringRedisSerializer;

/**
 * test StringRedisSerializer
 */
@Slf4j
public class StringRedisSerializerDemo {

    public static void main(String[] args) {
        StringRedisSerializer serializer = new StringRedisSerializer();
        String s = "hello";
        byte[] bytes = serializer.serialize(s);
        log.info("{} => {}", s, bytes);

        String str = serializer.deserialize(bytes);
        log.info("{} => {}", bytes, str);
    }

}

运行结果如下:

19:36:49.744 [main] INFO com.morris.spring.boot.redis.StringRedisSerializerDemo - hello => [104, 101, 108, 108, 111]
19:36:49.747 [main] INFO com.morris.spring.boot.redis.StringRedisSerializerDemo - [104, 101, 108, 108, 111] => hello

StringRedisSerializer只是对简单的字符串序列化,可读性好,可用于key的序列化。内部就是通过String类的new String(bytes) & string.getBytes()实现的序列化,源码如下:

public String deserialize(@Nullable byte[] bytes) {
    return (bytes == null ? null : new String(bytes, charset));
}

@Override
public byte[] serialize(@Nullable String string) {
    return (string == null ? null : string.getBytes(charset));
}

JdkSerializationRedisSerializer

JdkSerializationRedisSerializer的使用如下:

package com.morris.spring.boot.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.serializer.JdkSerializationRedisSerializer;

/**
 * test JdkSerializationRedisSerializer
 */
@Slf4j
public class JdkSerializationRedisSerializerDemo {

    public static void main(String[] args) {
        JdkSerializationRedisSerializer serializer = new JdkSerializationRedisSerializer();
        String s = "hello";
        byte[] bytes = serializer.serialize(s);
        log.info("{} => {}", s, new String(bytes));

        Object str = serializer.deserialize(bytes);
        log.info("{} => {}", new String(bytes), str);

        User user = new User("morris", 18);
        byte[] userBytes = serializer.serialize(user);
        log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

        User u = (User) serializer.deserialize(userBytes);
        log.info("{} => {}", new String(userBytes), u);
    }

}

运行结果如下:

19:51:11.240 [main] INFO com.morris.spring.boot.redis.JdkSerializationRedisSerializerDemo - hello => �� t hello
19:51:11.290 [main] INFO com.morris.spring.boot.redis.JdkSerializationRedisSerializerDemo - �� t hello => hello
19:51:11.299 [main] INFO com.morris.spring.boot.redis.JdkSerializationRedisSerializerDemo - [196]User(name=morris, age=18) => �� sr !com.morris.spring.boot.redis.User����}1)9 L aget Ljava/lang/Integer;L namet Ljava/lang/String;xpsr java.lang.Integer⠤���8 I valuexr java.lang.Number��?��?  xp   t morris
19:51:11.300 [main] INFO com.morris.spring.boot.redis.JdkSerializationRedisSerializerDemo - �� sr !com.morris.spring.boot.redis.User����}1)9 L aget Ljava/lang/Integer;L namet Ljava/lang/String;xpsr java.lang.Integer⠤���8 I valuexr java.lang.Number��?��?  xp   t morris => User(name=morris, age=18)

JdkSerializationRedisSerializer直接使用Java提供的序列化方式,效率高,占用空间少,可读行差,被序列化的对象必须实现Serializable接口,否则会抛出异常。

JdkSerializationRedisSerializer序列化底层使用的是ObjectOutputStream:

public void serialize(Object object, OutputStream outputStream) throws IOException {
    if (!(object instanceof Serializable)) {
        throw new IllegalArgumentException(getClass().getSimpleName() + " requires a Serializable payload " +
                "but received an object of type [" + object.getClass().getName() + "]");
    }
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);
    objectOutputStream.writeObject(object);
    objectOutputStream.flush();
}

JdkSerializationRedisSerializer反序列化底层使用的是ObjectInputStream:

public Object deserialize(InputStream inputStream) throws IOException {
    ObjectInputStream objectInputStream = new ConfigurableObjectInputStream(inputStream, this.classLoader);
    try {
        return objectInputStream.readObject();
    }
    catch (ClassNotFoundException ex) {
        throw new NestedIOException("Failed to deserialize object type", ex);
    }
}

Jackson2JsonRedisSerializer

public static void errorTest() {
    Jackson2JsonRedisSerializer<Object> serializer = new Jackson2JsonRedisSerializer<>(Object.class);

    User user = new User("morris", 18);
    byte[] userBytes = serializer.serialize(user);
    // [26]User(name=morris, age=18) => {"name":"morris","age":18}
    log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

    User u = (User) serializer.deserialize(userBytes);
    // java.util.LinkedHashMap cannot be cast to com.morris.spring.boot.redis.User
    log.info("{} => {}", new String(userBytes), u);
}

运行结果如下:

09:41:48.251 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - [26]User(name=morris, age=18) => {"name":"morris","age":18}
3 actionable tasks: 2 executed, 1 up-to-date
Exception in thread "main" java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.morris.spring.boot.redis.User
	at com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo.errorTest(Jackson2JsonRedisSerializerDemo.java:34)
	at com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo.main(Jackson2JsonRedisSerializerDemo.java:15)

直接使用Jackson2JsonRedisSerializer序列化Object任意对象时没问题,但是在进行反序列化时会抛出java.util.LinkedHashMap cannot be cast to XXX异常。

Jackson2JsonRedisSerializer创建时如果不使用Object,而是指定具体的对象User就不会抛出异常,序列化出来的json也不包含额外的信息。

public static void testNotObject() {
    Jackson2JsonRedisSerializer<User> serializer = new Jackson2JsonRedisSerializer<>(User.class);

    User user = new User("morris", 18);
    byte[] userBytes = serializer.serialize(user);
    // [26]User(name=morris, age=18) => {"name":"morris","age":18}
    log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

    User u = serializer.deserialize(userBytes);
    // {"name":"morris","age":18} => User(name=morris, age=18)
    log.info("{} => {}", new String(userBytes), u);
}

允许结果如下:

09:45:07.795 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - [26]User(name=morris, age=18) => {"name":"morris","age":18}
09:45:07.833 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - {"name":"morris","age":18} => User(name=morris, age=18)

这样做的缺点就是对不同的对象进行序列化时要创建不同的Jackson2JsonRedisSerializer,非常麻烦。

那么有没有一种方法能实现反序列化任意对象不抛出上面的异常呢?可以通过设置ObjectMapper的一个属性来解决。

public static void testEnableDefaultTyping() {
    Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);
    serializer.setObjectMapper(objectMapper);

    User user = new User("morris", 18);
    byte[] userBytes = serializer.serialize(user);
    // [64]User(name=morris, age=18) => ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}]
    log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

    User u = (User) serializer.deserialize(userBytes);
    // ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}] => User(name=morris, age=18)
    log.info("{} => {}", new String(userBytes), u);
}

运行结果如下:

09:50:55.843 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - [64]User(name=morris, age=18) => ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}]
09:50:55.894 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}] => User(name=morris, age=18)

可以看到对象序列化后会将class的全限定名写入到结果中,这样在反序列化时就能知道需要将数据反序列化成什么对象了。

objectMapper.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_FINAL);的含义就是对于除了一些原生类型(String、Double、Integer、Double)类型外的非常量(non-final)类型,类型将会序列化在结果上,以便可以在JSON反序列化正确的推测出值所属的类型。

上面的api已经过时了,可以使用下面的新api:

public static void testNewApi() {
    Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.activateDefaultTyping(objectMapper.getPolymorphicTypeValidator() ,
            ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.WRAPPER_ARRAY);
    serializer.setObjectMapper(objectMapper);

    User user = new User("morris", 18);
    byte[] userBytes = serializer.serialize(user);
    log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

    User u = (User) serializer.deserialize(userBytes);
    // PROPERTY {"@class":"com.morris.spring.boot.redis.User","name":"morris","age":18} => User(name=morris, age=18)
    // WRAPPER_ARRAY ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}] => User(name=morris, age=18)
    // WRAPPER_OBJECT {"com.morris.spring.boot.redis.User":{"name":"morris","age":18}} => User(name=morris, age=18)
    log.info("{} => {}", new String(userBytes), u);
}

运行结果如下:

09:55:32.821 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - [64]User(name=morris, age=18) => ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}]
09:55:32.878 [main] INFO com.morris.spring.boot.redis.Jackson2JsonRedisSerializerDemo - ["com.morris.spring.boot.redis.User",{"name":"morris","age":18}] => User(name=morris, age=18)

GenericJackson2JsonRedisSerializer

package com.morris.spring.boot.redis;

import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;

/**
 * test GenericJackson2JsonRedisSerializer
 */
@Slf4j
public class GenericJackson2JsonRedisSerializerDemo {

    public static void main(String[] args) {
        GenericJackson2JsonRedisSerializer serializer = new GenericJackson2JsonRedisSerializer();

        User user = new User("morris", 18);
        byte[] userBytes = serializer.serialize(user);
        // [71]User(name=morris, age=18) => {"@class":"com.morris.spring.boot.redis.User","name":"morris","age":18}
        log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

        User u = (User) serializer.deserialize(userBytes);
        // {"@class":"com.morris.spring.boot.redis.User","name":"morris","age":18} => User(name=morris, age=18)
        log.info("{} => {}", new String(userBytes), u);
    }
}

运行结果如下:

10:01:37.428 [main] INFO com.morris.spring.boot.redis.GenericJackson2JsonRedisSerializerDemo - [71]User(name=morris, age=18) => {"@class":"com.morris.spring.boot.redis.User","name":"morris","age":18}
10:01:37.485 [main] INFO com.morris.spring.boot.redis.GenericJackson2JsonRedisSerializerDemo - {"@class":"com.morris.spring.boot.redis.User","name":"morris","age":18} => User(name=morris, age=18)

从运行结果可以看出GenericJackson2JsonRedisSerializer确实如他的名字那样天生就支持泛型,他也是通过将类信息序列化到结果中实现的。

从GenericJackson2JsonRedisSerializer的构造方法源码中也可以看出是通过设置ObjectMapper的属性来实现,跟我们上面手动指定的配置一样。

public GenericJackson2JsonRedisSerializer(@Nullable String classPropertyTypeName) {

    this(new ObjectMapper());

    // simply setting {@code mapper.disable(SerializationFeature.FAIL_ON_EMPTY_BEANS)} does not help here since we need
    // the type hint embedded for deserialization using the default typing feature.
    registerNullValueSerializer(mapper, classPropertyTypeName);

    if (StringUtils.hasText(classPropertyTypeName)) {
        mapper.activateDefaultTypingAsProperty(mapper.getPolymorphicTypeValidator(), DefaultTyping.NON_FINAL,
                classPropertyTypeName);
    } else {
        mapper.activateDefaultTyping(mapper.getPolymorphicTypeValidator(), DefaultTyping.NON_FINAL, As.PROPERTY);
    }
}

FastJsonRedisSerializer

public static void testNotObject() {
    FastJsonRedisSerializer<User> serializer = new FastJsonRedisSerializer<>(User.class);

    User user = new User("morris", 18);
    byte[] userBytes = serializer.serialize(user);
    // [26]User(name=morris, age=18) => {"age":18,"name":"morris"}
    log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

    User u = (User) serializer.deserialize(userBytes);
    // {"age":18,"name":"morris"} => User(name=morris, age=18)
    log.info("{} => {}", new String(userBytes), u);
}

运行结果如下:

11:27:52.926 [main] INFO com.morris.spring.boot.redis.FastJsonRedisSerializerDemo - [26]User(name=morris, age=18) => {"age":18,"name":"morris"}
11:27:52.950 [main] INFO com.morris.spring.boot.redis.FastJsonRedisSerializerDemo - {"age":18,"name":"morris"} => User(name=morris, age=18)

FastJsonRedisSerializer与Jackson2JsonRedisSerializer一样不支持泛型,需要支持泛型请使用GenericFastJsonRedisSerializer。

GenericFastJsonRedisSerializer

package com.morris.spring.boot.redis;

import com.alibaba.fastjson.support.spring.GenericFastJsonRedisSerializer;
import lombok.extern.slf4j.Slf4j;

/**
 * test GenericFastJsonRedisSerializer
 */
@Slf4j
public class GenericFastJsonRedisSerializerDemo {
    public static void main(String[] args) {
        GenericFastJsonRedisSerializer serializer = new GenericFastJsonRedisSerializer();

        User user = new User("morris", 18);
        byte[] userBytes = serializer.serialize(user);
        // [70]User(name=morris, age=18) => {"@type":"com.morris.spring.boot.redis.User","age":18,"name":"morris"}
        log.info("[{}]{} => {}", userBytes.length, user, new String(userBytes));

        User u = (User) serializer.deserialize(userBytes);
        // {"@type":"com.morris.spring.boot.redis.User","age":18,"name":"morris"} => User(name=morris, age=18)
        log.info("{} => {}", new String(userBytes), u);
    }
}

运行结果如下:

11:29:09.886 [main] INFO com.morris.spring.boot.redis.GenericFastJsonRedisSerializerDemo - [70]User(name=morris, age=18) => {"@type":"com.morris.spring.boot.redis.User","age":18,"name":"morris"}
11:29:09.915 [main] INFO com.morris.spring.boot.redis.GenericFastJsonRedisSerializerDemo - {"@type":"com.morris.spring.boot.redis.User","age":18,"name":"morris"} => User(name=morris, age=18)

GenericFastJsonRedisSerializer与GenericJackson2JsonRedisSerializer一样会将类信息序列化到结果中。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ScrollRect滚动区域Content列表项数据钳制取值问题

问题 如下图示例&#xff0c;是一个选择日期、时间的日历控件&#xff0c;右侧小时与分钟的部分是两个Scroll Rect滚动区域组件&#xff0c;滚动到中间高亮部分表示选择&#xff0c;那么如何让滚动停止在合适的位置&#xff1f;避免出现如图所示的停在两个数据项中间的情况。 …

Slam十四讲之第一讲和第二讲,实践编程基础

目录 1.镜像寻找①方法1&#xff1a;百度网盘下载②方法2&#xff1a;在开源镜像网站上下载&#xff0c;③方法3&#xff1a;直接在Ubuntu官网下载 2 在VMware中创建虚拟机并安装Ubuntu18.043 安装VMware Tools4 初始系统中&#xff0c;部分软件的安装4.1 gcc 安装4.2 g安装4.3…

Word 插件实现读取excel自动填写

日常工作中碰到需要将EXCEL的对应数据记录填写到word文档对应的位置&#xff0c;人工操作的方式是&#xff1a; 打开exel表—>查找对应报告号的行—>逐列复制excel表列单元格内容到WORD对应的位置&#xff08;如下图标注所示&#xff09; 这种方法耗时且容易出错。实际上…

vcomp140.dll丢失怎样修复?多种方法教你修复

vcomp140.dll丢失算是一个比较常见的异常事件&#xff0c;在使用电脑的时候&#xff0c;有时候弹窗出现由于找不到vcomp140.dll&#xff0c;无法继续执行代码等&#xff0c;这种都是属于vcomp140.dll文件丢失&#xff0c;今天我们主要针对这个情况来给大家说说vcomp140.dll丢失…

自动化测试工具大盘点

本系列文章我们将带大家一起了解一下互联网大厂中通科技的自动化测试平台的搭建历程&#xff0c;从以下四个方面展开介绍&#xff1a;为什么要做这样一个统一的自动化测试平台&#xff1f;是如何做到统一的&#xff1f;平台上线后的收益&#xff0c;最后一部分会给大家分享一下…

CSDN 周赛 62 期

CSDN 周赛 62 期 参赛体验选择题1234编程题1、题目名称:覆盖面积2、题目名称:机器猫参赛体验 这次没有出填空题,好评。 选择题四个,基本上,对数据库比较熟悉的人,应该都可以全部答对的。 编程题两个,嗯。。。。就是上周偷偷摸摸更新出来的四个题目之二。还以为不会出…

levelx norFlash

levelx 文章目录 OverviewQuoteBriefDefinitionTheory 实现原理1.初始化流程2.写操作3.读操作4.回收函数 Overview 实现了flash的均衡摩擦&#xff0c;有针对nor 和 nand的接口 配合azure RTOS 以及xfile比较合适&#xff0c;单独使用不是很友好 Quote https://learn.micro…

C# Sdcb.Paddle2Onnx Paddle模型通过C#转换为ONNX模型

https://github.com/sdcb/PaddleSharp/blob/feature/2.5/docs/paddle2onnx.md 效果 项目 代码 using Sdcb.Paddle2Onnx; using System; using System.Collections; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing…

相对绝对定位父元素不设置宽度,根据子元素撑开(white-space: nowrap;)

要做一个如下的弹窗&#xff0c;很简单。但是当要切换成多语言或者数据是动态的话&#xff08;title可能会很长&#xff09;&#xff0c;那么弹窗固定宽度就不适用了。 有可能会出现下图的情况 也有可能出现下面的情况&#xff0c;文字被换行了&#xff08;有时候这种情况也是…

每日一练 | 华为认证真题练习Day77

1、如下图所示&#xff0c;主机A和主机B使用哪种网络设备可以实现通信&#xff1f; A. 路由器 B. 集线器 C. HUB D. 二层交换机 2、路由器输出信息如下&#xff0c;下列说法错误的是&#xff1f; A. Ethernet0/0/0接口的MTU值为1480 B. Ethernet0/0/0接口物理链路正常 C.…

5分钟体验墨迹天气API设计与调试,来看看你关心的城市天气吧~

1 准备工作 请务必完成华为云账号注册和实名认证&#xff0c;否则无法进行实操实验。 Step 1 >>>点我立即注册华为云账号<<< Step 2 >>>点我完成实名认证<<< 1.1 登录访问API Arts主页 1、点击访问API Arts主页&#xff0c;点击“申请…

项目管理工具大比拼:全方位评估各家优势

在现代企业中&#xff0c;项目管理已经成为了一个不可或缺的部分。而具有高效、易用、多样化功能的项目管理软件能够帮助企业更好地管理项目和任务&#xff0c;并提高团队生产力和效率。因此&#xff0c;在选择适合的项目管理软件时&#xff0c;需要对不同软件进行全方位比较和…

〖码银送书第三期〗《Python机器学习:基于PyTorch和Scikit-Learn》

前言 近年来&#xff0c;机器学习方法凭借其理解海量数据和自主决策的能力&#xff0c;已在医疗保健、 机器人、生物学、物理学、大众消费和互联网服务等行业得到了广泛的应用。自从AlexNet模型在2012年ImageNet大赛被提出以来&#xff0c;机器学习和深度学习迅猛发展&#xf…

1. HTML5的新特性

HTML5的新增特性主要是针对于以前的不足, 增了一些新的标签、新的表单和新的表单属性等。 这些新特性都有兼容性问题,基本是IE9以上版本的浏览器才支持, 如果不考虑兼容性问题,可以大量使用这些新特性。 1.1 HTML5 新增的语义化标签 ●<header> : 头部标签 ●<nav&…

优思学院|工厂如何从零开始开展TPM管理?

TPM管理的实施步骤&#xff0c;因应各企业的情况和特性&#xff0c;实施的方法会有点差异&#xff0c;但一般的基本步骤是以下表所表示。 这16个TPM管理的基本步骤&#xff0c;是将各企业之长处更加的发挥&#xff0c;且为了达成重点目标&#xff0c;组织全体的实施方法。 大…

【Spring | 资源处理】

Resource Resource 接口介绍核心方法常见接口优缺点 内置Resource实现UrlResourceClassPathResourceFileSystemResourcePathResourceServletContextResourceInputStreamResourceByteArrayResource Resource 接口 不幸的是&#xff0c;Java的标准Java.net.URL类和各种URL前缀的标…

Buck电路的原理及器件选型指南

Buck电路工作原理 电源闭合时电压会快速增加&#xff0c;当断开时电压会快速减小&#xff0c;如果开关速度足够快的话&#xff0c;是不是就能把负载&#xff0c;控制在想要的电压值以内呢? 假设12V降压到5V&#xff0c;也就意味着&#xff0c;MOS管开关需要42%时间导通&#…

java每日一题:手动触发垃圾回收(GC)

面试官: 首先&#xff0c;我想问一下&#xff0c;你能向我解释一下"手动触发Java垃圾回收"的过程吗&#xff1f;&#x1f914; 面试者: 在Java中&#xff0c;垃圾回收是自动进行的&#xff0c;由Java虚拟机&#xff08;JVM&#xff09;负责管理。但是&#xff0c;有…

Linux进程(一)---深入了解进程的概念及状态

目录 什么是进程 如何管理进程 描述进程 PCB到底是什么&#xff1f; PCB的内容分类 组织进程 查看进程 ps命令 通过系统调用获取进程标示符 getpid() getppid() 通过系统调用创建进程-fork初识 进程状态 运行态(R) 阻塞态(S) 阻塞态 挂起态 和就绪态的区别 …

【UE4 C++】07-角色运动设置

效果 可以看到我们可以通过WASD控制角色前后左右移动&#xff0c;通过鼠标控制摄像机旋转朝向。 步骤 1.在虚幻商城中搜索“Gideon”&#xff0c;将该免费资源添加到工程中&#xff08;大概2.6G&#xff09; 2. 打开之前创建的“PlayerCharacter” 选中网格体组件&#xff0…