59从零开始学Java之StringBuilder与StringBuffer

news2024/10/6 20:36:02

作者:孙玉昌,昵称【一一哥】,另外【壹壹哥】也是我哦

千锋教育高级教研员、CSDN博客专家、万粉博主、阿里云专家博主、掘金优质作者

前言

最近的这几篇文章,壹哥一直在给大家讲解字符串相关的内容。其实字符串按照可变性,可以分为不可变字符串与可变字符串。我们前面学习的String就属于不可变字符串,因为理论上一个String字符串一旦定义好,其内容就不可再被改变,这些内容我们已经在前面都学习过了。但实际上,还有另一种可变字符串,包括StringBuilder和StringBuffer两个类。那可变字符串有什么特点?又怎么使用呢?接下来就请大家跟我一起来学习吧。

-----------------------------------------------前戏已做完,精彩即开始---------------------------------------------

全文大约【6000】字,不说废话,只讲可以让你学到技术、明白原理的纯干货!本文带有丰富的案例及配图视频,让你更好地理解和运用文中的技术概念,并可以给你带来具有足够启迪的思考......

配套开源项目资料

Github:

GitHub - SunLtd/LearnJava

Gitee:

从零开始学Java: 从零开始学Java系列稀土掘金专栏地址:https://juejin.cn/column/7175082165548351546CSDN专栏地址:https://yiyige.blog.csdn.net/article/details/129377219?spm=1001.2014.3001.5502

一. 可变字符串

1. 简介

在Java中,我们除了可以通过String类创建和处理字符串之外,还可以使用StringBuffer和StringBuilder类来处理字符串。其中,String类定义的字符串内容不可变,所以String属于不可变字符串。而StringBuffer和StringBuilder定义的字符串内容可变,这两者属于可变字符串,并且StringBuffer和StringBuilder,对字符串的处理效率比String类更高。

2. 使用场景

有的小伙伴可能还是不太理解,字符串的使用并不是很难,咱们直接使用String来操作就可以了,为什么还要搞出来StringBuffer和StringBuilder这两个类?这不是找麻烦吗?其实这都是有原因的!

从底层原理来分析,String构建的字符串对象,其内容理论上是不能被改变的。一旦定义了String对象就无法再改变其内容,但很多时候我们还是需要改变字符串的内容的,所以String类就存在一定的短板。

另外从应用层面来分析,String字符串的执行效率其实是比较低的。举个例子,就比如常见的字符串拼接,很多人喜欢使用“+号”来拼接String字符串。其实如果是操作少量的字符串,使用String还凑活,一旦同时操作的字符串过多,String的效率就极低了。壹哥之前曾做过一个关于10万个字符串拼接的实验。同等条件下,利用“+”号进行拼接所需要的时间是29382毫秒,利用StringBuffer所需要的时间只有4毫秒,而StringBuilder所用的时间更是只需2毫秒,这效率真是天差地别!关于本实验,请大家参考如下链接:

高薪程序员&面试题精讲系列16之Java中如何拼接多个字符串?StringBuffer和StringBuilder的区别?

另外我们还可以通过下面这个稍微简单点的案例,来看看Java底层是如何处理字符串拼接的。

String str = "Hello" + "World";
System.out.println("str=" + str);

相信很多朋友都会用 “+”号 来进行字符串拼接,因为觉得该方式简单方便,毕竟 一 “+” 了事。那么利用 “+”号来拼接字符串是最好的方案吗?肯定不是的!如果我们使用JAD反编译工具对上述Java字节码进行反编译,你会发现不一样的结果,上述案例反编译后得到的JAD文件内容如下所示:

import java.io.PrintStream;

public class StringTest13
{

    public StringTest13()
    {
    }

    public static void main(String args[])
    {
        String s = "HelloWorld";
        System.out.println((new StringBuilder()).append("str=").append(s).toString());
    }
}

从反编译出来的JAD文件中我们可以看出,Java在编译的时候会把 “+”号操作符替换成StringBuilder的append()方法。也就是说,“+”号操作符在拼接字符串的时候只是一种形式,让开发者使用起来比较简便,代码看起来比较简洁,但底层使用的还是StringBuilder操作。

既然 “+”号 的底层还是利用StringBuilder的append()方法操作,那么我们为什么不直接使用StringBuilder呢?你说对吧?而且当我们需要操作大量的字符串时,更不推荐使用String,比如:

String str = "";
for (int i = 0; i < 10000; i++) {
    str = str + "," + i;
}

上面这段代码,虽然可以实现字符串的拼接,但是在该循环中,每次循环都会创建一个新的字符串对象,然后扔掉旧的字符串。如果是10000次循环,就会执行10000次这样的操作。而这些操作中的绝大部分字符串对象都是临时对象,最终都会被扔掉不用,这就会严重地浪费内存,并会严重影响GC垃圾回收的效率。

为了能提高拼接字符串的效率,Java给我们提供了StringBuffer和StringBuilder,它们都是可变对象,可以预分配缓冲区。当我们往StringBuffer或StringBuilder中新增字符时,不会创建新的临时对象,可以极大地节省了内存可以说,好处多多。

那么接下来壹哥就带领各位来学习StringBuffer、StringBuilder的用法吧。

二. StringBuffer

1. 简介

StringBuffer是一种可变的字符串类,即在创建StringBuffer对象后,我们还可以随意修改字符串的内容。每个StringBuffer的类对象都能够存储指定容量的字符串,如果字符串的长度超过了StringBuffer对象的容量空间,则该对象的容量会自动扩大。

另外我们在使用StringBuffer类时,比如每次调用toString()方法,都会直接使用缓存区的toStringCache 值来构造一个字符串,这每次都是对StringBuffer对象本身进行操作,而不会重新生成一个新对象。所以如果我们需要对大量字符串的内容进行修改,壹哥推荐大家使用StringBuffer。

2. 基本特性

StringBuffer作为一个可变字符串类,具有如下特性:

  • 具有线程安全性:StringBuffer中的公开方法都由synchronized关键字修饰,保证了线程同步;
  • 带有缓冲区:StringBuffer每次调用toString()方法时,都会直接使用缓存区的toStringCache值来构造一个字符串;
  • 内容可变性:StringBuffer中带有字符串缓冲区,我们可以通过数组的复制来实现内容的修改;
  • 自带扩容机制:StringBuffer可以初始化容量,也可以指定容量,当字符串长度超过了指定的容量后,可以通过扩容机制实现长度的变更;
  • 内容类型多样性:StringBuffer中可以存储多种不同类型的数据。

了解了StringBuffer的基本特性之后,请大家跟着壹哥来学习一下StringBuffer的基本用法吧。

3. 基本用法

3.1 常用API方法

StringBuffer作为一个字符串操作类,它有以下几个需要我们掌握的常用API方法,如下所示:

方法名称

方法作用

StringBuffer()

构造一个空的字符串缓冲区,并且初始化为 16个字符的容量

StringBuffer(int length)

创建一个空的字符串缓冲区,并且初始化为指定长度 length

的容量

StringBuffer(String str)

创建一个字符串缓冲区,并将其内容初始化为指定的字符串

内容 str,字符串缓冲区的初始容量为 16 加上字符串 str 的

长度

StringBuffer append(String s)

将指定的字符串追加到此字符序列后面

StringBuffer reverse()

将该字符序进行反转

StringBuffer delete(int start, int end)

移除该字符串中指定起始位置的子字符串

StringBuffer insert(int offset, int i)

将int类型的内容插入到该字符串的指定位置上

StringBuffer insert(int offset, String str)

将String类型的内容插入到字符串的指定位置上

StringBuffer replace(int start, int end, String str)

使用给定的新子串,替换字符串中指定起始位置上旧的子串

int capacity()

返回当前字符串的容量

char charAt(int index)

返回字符串中指定索引处的char值。

int indexOf(String str)

返回在该字符串中第一次出现指定子串的索引值

int indexOf(String str, int fromIndex)

从指定索引处开始,返回在该字符串中第一次出现指定子串

的索引值

int lastIndexOf(String str)

返回指定子串在此字符串中最后的索引值

int length()

返回字符串的长度,即字符个数

CharSequence subSequence(int start, int end)

根据指定的起、止值,返回一个新的子串

String substring(int start)

根据指定的起始值,返回一个新的子串

3.2 基本案例

知道了这些常用的API方法后,我们再通过一个案例来看看这些方法到底是怎么用的。

/**
 * @author 一一哥Sun
 */
public class Demo01 {

	public static void main(String[] args) {
		//创建StringBuffer对象
        StringBuffer sb = new StringBuffer("跟一一哥,");

        //在字符串后面追加新的字符串
        sb.append("学Java!");
        System.out.println(sb); 

        //删除指定位置上的字符串,从指定的下标开始和结束,下标从0开始
        sb.delete(2, 4);
        System.out.println(sb);//"一哥"

        //在指定下标位置上添加指定的字符串
        sb.insert(2, "123");
        System.out.println(sb);//跟一123,学Java!

        //将字符串翻转
        sb.reverse();
        System.out.println(sb);//!avaJ学,321一跟

        //将StringBuffer转换成String类型
        String s = sb.toString();
        System.out.println(s);
	}

}

3.3 append()用法

在以上几个方法中,壹哥再重点给大家说一下append()追加方法。该方法的作用是追加内容到当前StringBuffer对象的末尾,类似于字符串的连接。调用该方法以后,StringBuffer对象的内容也会发生改变。使用该方法进行字符串的连接,会比String更加节约内存。我们可以利用append()方法进行动态内容的追加,比如进行数据库SQL语句的拼接:

/**
 * @author 一一哥Sun
 */
public class Demo02 {
	public static void main(String[] args) {
		StringBuffer sb = new StringBuffer();
		String user = "yyg";
		String pwd = "123";
		
		//实现SQL语句的拼接
		sb.append("select * from userInfo where username=")
		.append(user)
		.append(" and pwd=")
		.append(pwd);

		System.out.println("sql="+sb.toString());
	}
}

StringBuffer的用法其实很简单,和String差不多,大家简单掌握即可。

4. 配套视频

与本节内容配套的视频链接如下:

External Player - 哔哩哔哩嵌入式外链播放器

三. StringBuilder

1. 简介

要想实现可变字符串的操作,其实还有另一个StringBuilder类,该类是在Java 5中被提出的。它和 StringBuffer的基本用法几乎是完全一样的,关于StringBuilder的用法,壹哥不会讲解太多。

但StringBuilder和StringBuffer最大的不同在于,StringBuilder的各个方法都不是线程安全的(不能同步访问),在多线程时可能存在线程安全问题,但StringBuilder的执行效率却比StringBuffer快的多。

实际上大多数情况下,我们都是在单线程下进行字符串的操作,所以使用StringBuilder并不会产生线程安全问题。所以针对大多数的单线程情况,壹哥还是建议大家使用StringBuilder,而不是StringBuffer,除非你们的项目对线程安全有着明确的高要求。

2. 特性

StringBuilder作为可变字符串操作类,具有如下特性:

  • StringBuilder是线程不安全的,但执行效率更快;
  • 适用于单线程环境下,在字符缓冲区进行大量操作的情况。

3. 基本用法

StringBuilder的API方法和基本用法与StringBuffer一样,此处略过。

4. 配套视频

与本节内容配套的视频链接如下:

External Player - 哔哩哔哩嵌入式外链播放器

四. 扩容机制(重点)

扩容机制应该是本篇文章中的一个重难点,所以壹哥要结合源码,单独列出一节给大家仔细分析一下。

在常规的用法上面,StringBuffer和StringBuilder基本没有什么差别。两者的主要区别在于StringBuffer是线程安全的,但效率低,StringBuilder是线程不安全的,但效率高。不过在扩容机制上,StringBuffer和StringBuilder是一样的。所以在这里,壹哥就以StringBuffer为例,只给大家分析一个类即可。

1. 继承关系

首先我们可以追踪一下StringBuffer的源码,看看它继承自哪个父类。

从上图可以看出,StringBuffer和StringBuilder其实都是继承自AbstractStringBuilder,所以StringBuffer与StringBuilder这两者可以说是“亲兄弟”的关系,它们俩有一个共同的抽象父类AbstractStringBuilder,如下所示:

2. AbstractStringBuilder抽象父类

壹哥在之前给大家讲解抽象类时就跟大家说过,抽象类可以将多个子类个性化的实现,通过抽象方法交由子类来实现;而多个子类共性的方法,可以放在父类中实现。StringBuffer和StringBuilder的共同父类AbstractStringBuilder就是一个抽象类,在这个父类中把StringBuffer和StringBuilder的一些共同内容进行了定义。比如在该类中,就定义了一个定长的字节数组来保存字符串,后面当我们利用append()方法不断地追加字符串时,如果该字符串的长度超过了这个数组的长度,就会利用数组复制的方式给该数组进行扩容。

3. 容量设置

另外壹哥在前面给大家讲解StringBuffer的API方法时,也给大家说过StringBuffer有3个构造方法。而无论是哪个构造方法都可以设置存储容量,即使是默认的构造方法也会有值为16的存储容量,如下图所示:

4. 扩容过程(核心)

4.1 StringBuffer#append()方法

虽然StringBuffer有默认的容量设置,也有自定义的容量设置,但在实际开发过程中,容量还是有可能不够用。这时就会根据追加的字符串长度进行动态扩容,那么这个扩容过程到底是怎么样的呢?其实StringBuffer的扩容需要利用append()方法作为入口,我们先来看看append()方法的源码,如下所示:

4.2 AbstractStringBuilder#append()方法

在StringBuffer的append()方法中,你会发现实际上真正的实现是通过super关键字,在调用父类的append()方法,所以我们继续往下追踪,此时进入到AbstractStringBuilder类中的append()方法中,如下图所示:

此时我们看到了一个ensureCapacityInternal()方法,从字面意思来理解,该方法是用于确保内部容量。传递给该方法的个参数是count+len,也就是 原有字符串的长度+新追加的字符串长度,即append后字符串的总长度

4.3 ensureCapacityInternal()方法

那么ensureCapacityInternal()接受了新字符串的总长度之后会发生什么变化呢?我们必须进入到ensureCapacityInternal()方法的内部来探究一番,源码如下:

在该方法中,我们首先看到了一个二进制位的右移运算。value.length是字符数组的长度,结合coder参数进行右移运算,得到字符串的原有容量。这里的coder参数是一种编码方式,如果字符串中没有中文,默认是采用Latin1编码,如果有中文则会采用UTF-16编码。因为UTF-16编码中文时需要两个字节,也就是说,只要字符串中含有中文,value字节数组中是每两位对应一个字符。

然后会判断新追加的字符串长度是否超过了value字节数组的长度,如果新字符串的长度大于value字节数组的长度,则说明需要给该字节数组进行扩容。接着就会利用用Arrays.copyOf()方法,将当前数组的值拷贝给newCapacity()个长度的新数组,最后再重新赋值给value字节数组。在扩容的过程中,主要是利用数组复制的方法来实现!

4.4 newCapacity()方法

其实讲到现在,关于StringBuffer的扩容,基本原理壹哥已经给大家讲清楚了,但我们还可以继续深入看看newCapacity()这个方法的实现过程与返回值,它与数组扩容密切相关。

该方法的大致作用就是,获取value数组的原有长度和待追加的新字符串长度,利用ArraysSupport.newLength()方法计算出扩容后新数组的长度length,并最终返回该length。如果length的值等于Integer的最大值,说明我们传递过来的字符串太长了,就会直接触发一个内存溢出的异常。

4.5 newLength()方法

而ArraysSupport.newLength()方法的内部实现,主要是利用Math.max()方法实现的,如下所示:

4.6 小结(重点)

至此,壹哥就把StringBuffer的扩容过程给大家分析完毕了,最后,壹哥再给大家把这个扩容的核心思路总结一下,StringBuffer扩容机制的基本规则如下:

  • 如果一次追加的字符长度超过了当前设置的容量,则会按照 当前容量*2+2 进行扩容;
  • 如果一次追加的长度不仅超过了初始容量,而且按照 当前容量*2+2 扩容一次还不够,其容量会直接扩容到与所添加字符串长度相等的长度
  • 之后如果还要再追加新的字符内容,依然会按照 当前容量*2+2 进行扩容。

5. 验证案例

最后为了验证上述结论是否正确,壹哥再给大家设计如下案例,供大家思考验证。

/**
 * @author 一一哥Sun 
 * V我领资料:syc_2312119590 
 * 各平台都有壹哥的同名博客哦
 */
public class Demo03 {
	// 扩容机制
	public static void main(String[] args) {
		//无参构造方法,初始容量默认为16
		StringBuffer sb = new StringBuffer();

		//使用StringBuffer的capacity()方法查看其当前容量
		System.out.println("默认初始化容量capacity=" + sb.capacity() + ",默认长度length=" + sb.length());

		//一次追加20个字符,因为超过了初始容量,因此会扩容16*2+2=34
		sb.append("11111111112222222222");
		System.out.println("扩容一次的capacity()=" + sb.capacity() + ",扩容一次后的length=" + sb.length());
		
		StringBuffer sb02 = new StringBuffer();
		//再次添加50个字符,不仅超过了初始容量16,而且按照 当前容量*2+2 进行扩容(34)后,依然存储不下,
        //则直接将容量扩容到新追加的字符串长度50
		sb02.append("11111111112222222222333333333344444444445555555555");	
		System.out.println("再次扩容后的capacity="+sb02.capacity()+",再次扩容后的长度length():"+sb02.length());
	}
}

从上述实验的执行结果中,你会发现StringBuffer与StringBuilder就是按照上述规则进行扩容的。

6. 配套视频

与本节内容配套的视频链接如下:

External Player - 哔哩哔哩嵌入式外链播放器

-------------------------------------------------正片已结束,来根事后烟-----------------------------------------------

五. 结语

至此,我们就把字符串相关的内容都学习完了,接下来壹哥就把今天的重点内容给大家总结一下,尤其是String、StringBuffer与StringBuilder的区别有哪些。

1. 相同点

String、StringBuffer、StringBuilder三者共同之处,它们都是final类,不允许被继承,这样设计主要是从性能和安全性上考虑的。

2. 不同点

String、StringBuffer、StringBuilder这三个类之间的区别主要体现在3个方面,即 运行速度、线程安全功能可变性 这4个方面。

在运行速度方面:三者之间的执行速度由快到慢为:StringBuilder > StringBuffer > String

在线程安全方面:StringBuilder是线程不安全的,而StringBuffer是线程安全的。

如果一个StringBuffer对象在字符串缓冲区被多个线程使用,StringBuffer中很多方法都带有synchronized关键字,可以保证线程是安全的。但StringBuilder的方法中则没有该关键字,所以不能保证线程安全,有可能在进行线程并发操作时产生一些异常。所以如果要进行多线程环境下的操作,考虑使用StringBuffer;在单线程环境下,建议使用速度StringBuilder。

在功能方面:String实现了三个接口,即Serializable、Comparable<String>、CarSequence;

StringBuilder和StringBuffer实现了两个接口,Serializable、CharSequence,相比之下String的实例可以通过compareTo方法进行比较,其他两个不可以。

在可变性方面:String字符串是不可变的,StringBuilder与StringBuffer是可变的。

3. 最后总结一下

String:适用于少量字符串操作的情况;

StringBuilder:适用于单线程环境下,在字符缓冲区进行大量操作的情况;

StringBuffer:适用多线程环境下,在字符缓冲区进行大量操作的情况;

使用场景当修改字符串的操作比较多时,可以使用StringBuilder或StringBuffer;在要求线程安全的情况下用StringBuffer,在不要求线程安全的情况下用StringBuilder。

另外如果你独自学习觉得有很多困难,可以加入壹哥的学习互助群,大家一起交流学习。

六. 今日作业

在给定的字符串“ABCDEFGhijklmn1234567”中,随机获取4个字符,并使用 StringBuilder拼接成字符串。随机获取到的4个字符中可以出现重复字符。

提示:大家可以通过创建随机数对象来实现

java.util.Random。
java.util.Random random = new java.util.Random();
random.nextInt(100); //可以获取到 0~99 中任意一个随机数

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

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

相关文章

Linux内核分析与应用8-文件系统

本系列是对 陈莉君 老师 Linux 内核分析与应用[1] 的学习与记录。讲的非常之好&#xff0c;推荐观看 留此记录&#xff0c;蜻蜓点水,可作抛砖引玉 8.1 虚拟文件系统的引入 Linux文件系统中最重要的一个概念: 索引节点 Inode 文件系统是具体到分区的,所以不同分区格式化时,可以是…

Seata在Liunx环境启动配置指定JVM大小

Seata从官网下载下来默认分配的内存为2048MB,测试环境因为部署的程序比较多&#xff0c;给Seata分配2048MB内存也显得很奢侈于是在程序启动的时候配置Seata的内存 bin目录下面一个有四个脚本 在Liunx启动Seata我们需要在seata-setup.sh设置JVM seata-setup.sh设置JVM参考Liu…

DT Paint Effects工具(二)

混合笔刷 Paint Effects面板 画布菜单 笔刷和分辨率 高级笔划节点 最小-最大剪裁 笔刷类型 控制通道 笔刷轮廓 必须的物体上用 扭曲 网格设置和网格环境 刺 着色属性 照明Paint Effects 阴影 辉光

考研英语笔记:日本色情业的冰山一角

微信里很多考友说自己撑不住了&#xff0c;是的&#xff0c;这确实是考研过程中&#xff0c;最难熬的一段时光。 这就如&#xff0c;在狭窄的隧道中&#xff0c;前面只有一丝光亮。而后面&#xff0c;漆黑一片&#xff0c;早已没有了退路。 放弃是不可能了。但想拼却又觉得就那…

数据结构-时间复杂度/空间复杂度

Hello&#xff0c;好久没有更新了哦&#xff0c;已经开始学习数据结构了&#xff0c;这篇文章呢就是对刚学数据结构所接触到的时间复杂度进行一个分享哦&#xff0c;如果有错误之处&#xff0c;大家记得拍拍我哦~ 既然要讨论时间/空间复杂度&#xff0c;那我们就得知道时间/空…

【提醒】警惕骗子会议

不要相信以下两个网站所检索到的任何内容&#xff1a; Conferences All Over The World | Conference Index&#xff0c;警惕理由&#xff1a;它支持自己创建会议&#xff0c;也就是你都能去创建个会议&#x1f605;World Academy of Science, Engineering and Technology&…

Trie树【数组实现】

全文目录 Trie的表现形式数组实现 Trie 树代码 Trie的表现形式 Trie树主要用来实现字符串的存储和快速查找&#xff0c;其表现形式类似一颗多叉树&#xff0c;每个节点表示字符串的一个字符。由于可能会存在类似 "abc" 和 "abcde" 这样的数据&#xff0c;…

合成游戏开发方案

合成游戏是一种深受玩家喜爱的游戏类型&#xff0c;它将各种不同的元素结合起来&#xff0c;以创新的方式吸引玩家。在本文中&#xff0c;我们将探讨一种合成游戏的开发方案&#xff0c;包括游戏目标、游戏机制、游戏关卡、游戏核心元素以及未来发展方向。 游戏目标 我…

WebSocket的优缺点

WebSocket的优缺点 1. WebSocket概念 1.1 WebSocket优点 低延迟全双工长期运行双向实时通信 1.2 什么是心跳机制 为了保持WebSocket稳定的长连接,在建立连接后,服务器和客户端之间需要通过心跳包来保持连接状态,以防止连接因长时间没有数据传输而被切断. 心跳包是一直特殊…

国内外大语言模型调研(更新到2023.09.12)

目录 国外 OpenAI-ChatGPT Anthropic-Claude Google-Bard 国内 百度-文心一言 清华大学&智谱AI-ChatGLM 百川智能-百川大模型 科大讯飞-星火 阿里-通义千问 360-360智脑 腾讯-混元大模型 华为-盘古大模型 字节跳动-云雀大模型 好未来-MathGPT 商汤科技-商量…

abb PPC902AE101 3BHE010751R0101控制板

通信接口&#xff1a; 控制板通常配备了多种通信接口&#xff0c;以便与其他设备和系统进行数据交换。这些接口可能包括以太网、串行通信、Modbus等。 处理能力&#xff1a; 控制板可能具有一定的数据处理和计算能力&#xff0c;以执行控制算法、数据处理或逻辑功能。 数据存…

HiAI Foundation助力端侧音视频AI能力,高性能低功耗释放云侧成本

过去三年是端侧AI高速发展的几年&#xff0c;华为在2020年预言了端侧AI的发展潮流&#xff0c;2021年通过提供端云协同的方式使我们的HiAI Foundation应用性更进一个台阶&#xff0c;2022年提供视频超分端到端的解决方案&#xff0c;在2023HDC大会上&#xff0c;HiAI Foundatio…

喜讯连连!疆程重磅发布全球独家3.6 TFT- LCD AR-HUD及CMS产品及解决方案,并斩获年度TOP10供应商

9月7日至8日&#xff0c;2023世界显示产业大会在成都盛大启幕&#xff0c;同期由BOE&#xff08;京东方&#xff09;承办的“Define the Future 智能座舱生态论坛”&#xff0c;合肥疆程技术有限公司创始人兼总经理康栋受邀出席并发布两款重磅座舱解决方案。 本次论坛以“智能座…

VRTK4⭐二.VRTK4的项目基础配置

文章目录 &#x1f7e5; 硬件基本配置&#x1f7e7; 设置XR Plug-in Management&#x1f7e8; 添加项目Tilia&#x1f7e9; 配置项目Hierarchy &#x1f7e5; 硬件基本配置 解决使用OpenXR,HTC头显正常追踪,但手柄无法使用的问题. 问题如下: 当我们按照官方的标准流程配置完Op…

消息队列(一):需求分析

为什么要做这样一个项目&#xff1f; 首先&#xff0c;我们在之前学习的时候&#xff0c;就认识了一下 生产者消费者模式&#xff0c;这样一个模式有两大好处&#xff1a; 解耦合 本来有个分布式系统&#xff0c;A服务器 调⽤ B服务器&#xff08;A给B发请求&#xff0c;B给A…

中国智能卡车“遥遥领先”:卡车NOA落地5000万公里0事故,全球首个

智能车参考 | 公众号 AI4Auto 成熟的“擎天柱”&#xff0c;已经可以自己出去赚钱了。 此时此刻&#xff0c;遍及华东、华北、华南、西北…几乎全国所有主要货运干线上&#xff0c;都有智能重卡承运商单。 高速路段由卡车智能驾驶系统完全承担驾驶任务&#xff0c;自主控制油门…

中国社科院大学与美国杜兰大学能源管理硕士项目——喜欢可抵万难,加油!

人生起起伏伏&#xff0c;在我们与生活较量的过程中&#xff0c;每克服一道难题&#xff0c;便赢得了自我成就的依仗。慢慢的&#xff0c;我们放下了名利、物质和虚荣&#xff0c;但决不放弃对世界的求知欲以及对知识的渴望&#xff0c;虽然在职读研很苦很累&#xff0c;但喜欢…

【CesiumJS入门】(10)绘制多边形(动态实时画面)

前言 如果你是在寻求解决方案&#xff0c;可以直接用cesium-draw这个插件。 鼠标左键添加点、右键完成绘制,单击右侧弹窗关闭按钮清空绘制。参考沙盒示例&#xff1a;Drawing on Terrain 直接上代码了 /** Date: 2023-07-12 18:47:18* LastEditors: ReBeX 420659880qq.com* L…

安防监控/视频汇聚/云存储/AI智能视频分析平台EasyCVR下级海康设备无法级联是什么原因?

安防视频监控平台/视频集中存储/云存储/磁盘阵列EasyCVR可拓展性强、视频能力灵活、部署轻快&#xff0c;可支持的主流标准协议有国标GB28181、RTSP/Onvif、RTMP等&#xff0c;以及支持厂家私有协议与SDK接入&#xff0c;包括海康Ehome、海大宇等设备的SDK等。 有用户反馈&…

Excel、Jira、Bugfree 应该选哪个做bug管理?深度对比

如何选择最适合您团队的Bug管理系统&#xff1f;本指南提供了全面的选型建议&#xff0c;并深度对比了7类主流工具如PingCode、Jira、 Mantis等&#xff0c;涵盖功能、成本、易用性等多个关键因素。适用于软件开发团队、项目经理和决策者。 一、适合的BUG管理工具在产品开发中的…