String、StringBuffer和StringBuilder的区别(面试题)

news2024/11/24 8:48:07

目录

一、介绍String、StringBuffer和StringBuilder三大类

1.String类

2.StringBuffer类

3.StringBuilder类

4.什么是字符串常量池

4.StringBuilder类为什么不需要同步进行同步操作

二、关于String、StringBuffer和StringBuilder常见的面试题

1.为什么String是不可变的

2.StringBuffer和StringBuilder之间有什么区别?

3.为什么在频繁字符串拼接或修改的情况下,使用StringBuilder比使用String更高效?

4.如何选择String、StringBuffer和StringBuilder之间的适当类型?


一、介绍String、StringBuffer和StringBuilder三大类

1.String类

java.lang.String是Java中一个非常重要的类,用于表示和操作字符串。以下是有关String类的一些关键点:

  1. 不可变性(Immutability)String对象一旦创建,其值不可更改。这意味着当尝试修改String对象时,实际上是创建了一个新的字符串对象。这个特性使得String具有线程安全性和缓存的潜力。

  2. 字符串常量池(String Pool):为了提高性能和节省内存,Java使用了字符串常量池。字符串常量池是一个特殊的内存区域,用于存储字符串常量。当创建一个字符串字面量时(如String str = "Hello"),如果常量池中已经存在相同内容的字符串,就会直接返回常量池中的引用,而不会创建新的对象。

  3. 字符串操作String类提供了各种方法用于对字符串进行操作,如拼接(concat()+操作符)、分割(split())、提取子串(substring())及其他字符串处理方法(例如大小写转换、字符替换、字符串比较等)。

  4. 不可变性的优势

    • 线程安全:String对象的不可变性使其在多线程环境下是线程安全的,不需要额外的同步措施。
    • 缓存和性能优化:由于字符串是不可变的,可以在编译期间进行字符串的共享和缓存,提高程序的性能和效率。
  5. 字符串比较String类重写了equals()hashCode()方法,用于比较两个字符串的内容是否相等。

    • equals()方法比较字符串的内容是否相等。
    • ==操作符比较两个字符串对象的引用是否相等。
  6. 字符串拼接

    • 如果需要拼接少量字符串,通常使用+操作符或concat()方法。
    • 对于大量拼接操作,应该使用StringBuilderStringBuffer,它们在性能上优于多次字符串拼接。
  7. 编码与字符集String类支持在不同的字符集之间进行转换,例如使用getBytes()方法将字符串转换为字节数组,或使用getBytes(charset)方法指定特定字符集进行转换。

2.StringBuffer类

StringBuffer类是Java提供的一个可变字符串序列类,在java.lang包中定义。它与String类相似,但有一个重要的区别:String类是不可变的,即创建后不能更改其内容,而StringBuffer类则可以在原地修改字符串

以下是StringBuffer类的一些重要特性:

  1. 可变性:StringBuffer类的主要特征是其内容是可变的,可以在原地修改字符串。这使得我们可以执行插入、删除和替换等操作,而无需创建新的字符串对象。

  2. 线程安全:StringBuffer是线程安全的,即多个线程可以同时访问和修改同一个StringBuffer对象的内容,而不会导致数据不一致。它的方法都被synchronized关键字修饰,这样可以保证在多线程环境下的线程安全性。

  3. 性能:由于StringBuffer是可变的,避免了创建大量中间字符串的开销。这在频繁拼接和修改字符串的场景中非常有用,因为不需要每次操作都创建新的字符串对象,而是直接对原始字符串进行修改。

  4. API丰富:StringBuffer类提供了许多方法来操作和修改字符串。除了常用的添加、插入和删除字符串的方法外,还有方法可以反转字符串、替换子串、截取子串等。这使得StringBuffer具有强大的功能和灵活性。

需要注意的是,由于StringBuffer是为了线程安全而设计的,所以在单线程环境下,可以使用性能更好的StringBuilder类,它与StringBuffer类类似,但不是线程安全的。

下面是一个使用StringBuffer的示例代码:

StringBuffer sb = new StringBuffer();
sb.append("Hello");
sb.append(" ");
sb.append("World");
sb.insert(5, ","); // 在第5个字符位置插入逗号
sb.delete(5, 6); // 删除第5个字符
sb.reverse(); // 反转字符串
System.out.println(sb.toString()); // 输出:dlroW, olleH

通过使用StringBuffer类,我们可以方便地进行字符串的动态操作和修改,并能够高效地处理字符串操作的需求。

小贴士:

使用synchronized修饰实例方法时,它将锁定当前实例对象。只有获得锁的线程才能执行这个方法,其他线程需要等待锁释放后才能访问该方法。

3.StringBuilder类

StringBuilder类是Java提供的一个可变字符串序列类,与StringBuffer类类似,但不同的是StringBuilder不是线程安全的。StringBuilder类位于java.lang包中。

以下是StringBuilder类的一些重要特性:

  1. 可变性:StringBuilder类的主要特点是其内容是可变的,可以在原地修改字符串。与String类相比,StringBuilder类更加灵活,因为它允许插入、删除和替换等操作,而无需创建新的字符串对象。

  2. 非线程安全:与StringBuffer类不同,StringBuilder类不是线程安全的。也就是说,在多个线程同时访问和修改同一个StringBuilder对象时,可能会导致数据不一致。因此,如果在多线程环境下使用可变字符串,应该使用线程安全的StringBuffer类。

  3. 性能:由于StringBuilder是可变的,避免了创建大量中间字符串的开销,提高了性能。在单线程环境下,StringBuilder比StringBuffer更加高效,因为它不需要进行同步操作

  4. API丰富:StringBuilder类提供了许多方法来操作和修改字符串。它具有与StringBuffer类相同的API,包括添加、插入、删除、反转、替换和子串截取等方法。这使得StringBuilder具有强大的功能和灵活性。

在单线程环境下,通过使用StringBuilder类,我们可以方便地进行字符串的动态操作和修改,并能够高效地处理字符串操作的需求。但在多线程环境下,建议使用线程安全的StringBuffer类,以确保数据的一致性。

4.什么是字符串常量池

字符串常量池是Java中一种特殊的内存区域,用于存储字符串常量。它的主要特点是字符串常量池中的字符串是不可变的,即创建后不能被修改。

String s1 = "Hello"; // 字符串常量池中创建了一个字符串对象"Hello"
String s2 = "Hello"; // 由于字符串常量池中已存在相同内容的字符串对象"Hello",所以直接引用已存在的对象
String s3 = new String("Hello"); // 在堆内存中创建了一个新的字符串对象"Hello"
String s4 = new String("Hello"); // 在堆内存中创建了另一个新的字符串对象"Hello"

System.out.println(s1 == s2); // 输出:true,s1和s2引用同一个字符串对象
System.out.println(s1 == s3); // 输出:false,s1和s3引用不同的字符串对象
System.out.println(s3 == s4); // 输出:false,s3和s4引用不同的字符串对象
System.out.println(s1.equals(s3)); // 输出:true,s1和s3的值相等

在代码执行过程中,字符串常量池中会维护一个字符串常量的池,以避免重复创建相同内容的字符串对象。当我们使用字符串直接赋值或使用字符串字面量创建字符串对象时,会先在字符串常量池中查找是否已存在相同内容的字符串对象,如果存在,则直接引用已存在的对象;如果不存在,则在字符串常量池中创建一个新的字符串对象。而使用new关键字创建字符串对象时,无论字符串常量池中是否存在相同内容的字符串对象,都会在堆内存中创建一个新的字符串对象。

需要注意的是,使用字符串常量池可以节省内存,但在进行字符串拼接等频繁修改字符串内容的操作时,建议使用StringBuilder或StringBuffer类,以避免不必要的对象创建和内存开销。

再举个例子方便理解

String s1 = "abc";
String s2 = new String("abc");
String s3 = "abc";
String s4 = new String("abc");  
//创建了几个String对象

我们简单分析一下:

1.String s1 = "abc";:这行代码会在字符串常量池中创建一个String对象"abc"。如果常量池中已经有相同内容的对象,则直接引用已存在的对象。

2.String s2 = new String("abc");:这行代码会在堆内存中创建一个新的String对象"abc",因为使用了new关键字,无论常量池中是否有相同内容的对象,都会创建一个新的对象。

3.String s3 = "abc";:这行代码不会创建新的对象,而是将常量池中已存在的对象引用赋值给s3。

4.String s4 = new String("abc");:这行代码会在堆内存中创建另一个新的String对象"abc",即使常量池中已有相同内容的对象。

所以,总共创建了3个String对象。其中s1和s3引用了常量池中的同一个对象,而s2和s4是根据new关键字在堆内存中创建的新对象。

4.StringBuilder类为什么不需要同步进行同步操作

因为StringBuilder类不是线程安全的,所以在多个线程并发访问和修改同一个StringBuilder对象时,可能会导致数据不一致的问题。但是,由于StringBuilder类不需要进行同步操作,所以在单线程环境下,它的性能要比StringBuffer类略好。

小贴士:

并发访问是指多个线程或进程同时访问共享资源的行为。当多个线程或进程尝试同时读取、写入或修改同一个共享资源时,就会发生并发访问。

在并发访问的情况下,由于线程或进程的执行是并行的和交替的,可能会导致以下问题:

  1. 竞态条件(Race Condition):当多个线程或进程同时尝试对同一个资源进行写入操作时,由于执行顺序的不确定性,可能会导致结果的不确定性或错误的结果。

  2. 数据不一致:当多个线程或进程同时修改共享资源时,如果不进行适当的同步操作,可能会导致数据的不一致性,即数据被修改了一部分,但其他线程或进程可能看到的是修改之前的数据。

  3. 死锁(Deadlock):当多个线程或进程在等待其他线程或进程释放资源时,形成循环等待的状态,导致所有线程或进程无法继续执行。

并发访问是常见的多线程编程中的一个重要概念。在处理并发访问时,需要使用适当的同步机制(例如锁、信号量、原子操作等)来确保数据的一致性和并发访问的正确性。

二、关于String、StringBuffer和StringBuilder常见的面试题

1.为什么String是不可变的

String被设计为不可变的主要原因是为了提高性能、安全性和字符串常量池的利用。下面是关于为什么String是不可变的以及它的底层数组逻辑的解释:    

            1.性能优化:由于String是不可变的,一旦创建,其值不可更改。这意味着字符串可以被缓存,重复使用,以提高性能。在字符串常量池中,如果存在相同值的字符串常量,可以直接引用已存在的对象,避免了创建多个相同值的对象。  

            2.线程安全:由于String是不可变的,它可以在多线程环境中被共享,而不需要额外的同步措施。每个线程操作的是自己的副本,不会相互干扰,避免了线程安全问题。  

            3.哈希散列优化:由于String是不可变的,它的哈希值(通过 hashCode() 方法获取)只需要计算一次,并且可以缓存起来。这对于字符串的快速插入、查找和比较非常有利。                  4.底层数组逻辑:String的底层实现是一个字符数组(char[]),用于存储字符串的内容。当创建一个String对象时,它的值被存储在该数组中,并且数组的长度被固定下来,无法进行扩展或缩小。  

            5.字符串修改的副作用:由于String是不可变的,每次对字符串进行修改都会创建新的字符串对象。这意味着在修改字符串时,需要使用额外的内存来存储新字符串对象,并且旧的字符串对象变得不可达,最终被垃圾回收。

总结起来,String是不可变的是为了提高性能、保证线程安全性、优化哈希散列以及利用字符串常量池。它的底层是一个字符数组,一旦创建,其值无法修改,需要创建新的String对象来表示修改后的字符串。

小贴士:

从Java 9版本开始,Java引入了Compact Strings特性,String的底层实现有所改变,对于大部分字符集,String不再是一个简单的字符数组。

Compact Strings特性的引入是为了提高存储效率。在旧的实现中,每个字符都使用2个字节(16位)进行存储,即使是只需要1个字节的ASCII字符。这样会浪费空间,尤其是当存储大量ASCII字符的时候。Compact Strings通过存储不同长度的字符数据来达到节省空间的目的。 具体实现方式是,String对象的内部包含一个字节数组(byte[])和一个标识长度的字段。当字符串仅包含ASCII字符时,字符数据将会以字节的形式存储在字节数组中,每一个字节对应一个字符。当字符串包含任何非ASCII字符时,会采用其他方式进行存储,以便支持更大的字符集。这样的实现方式在大部分情况下仍然可以以字符数组的方式访问和操作字符串数据,特别是当字符串只包含ASCII字符时。只有在需要访问字符串的字节表示形式时,新的实现可能需要进行一些额外的转换操作

总结:在不同版本的Java中,String的底层实现可能会有所区别。

2.StringBuffer和StringBuilder之间有什么区别?

我从以下几点分别来说明StringBufferStringBuilder之间的区别

线程安全性

StringBuffer是线程安全的。它的方法是通过synchronized关键字进行同步的,因此在多线程环境下使用是安全的。多个线程可以同时访问和修改同一个StringBuffer对象,不会导致数据冲突或并发修改的问题。
StringBuilder是非线程安全的。它的方法没有进行同步,没有额外的同步开销,因此在单线程环境下可以获得更好的性能。但是,在多线程环境下,如果多个线程同时访问和修改同一个StringBuilder对象,可能会导致数据不一致的问题。

性能

StringBuffer的方法使用synchronized关键字进行同步,因此在多线程环境下安全可靠,但会带来一定的性能开销。如果不涉及多线程操作,使用StringBuffer可能会导致性能略低。
StringBuilder的方法没有进行同步,没有额外的同步开销,因此在单线程环境下性能更好。因为它不需要处理线程安全性,所以通常比StringBuffer快。
 

可变性

StringBuffer和StringBuilder都提供了可变的字符串操作,如append()、insert()、delete()等。它们可以方便地进行字符串的修改和拼接。
StringBuffer的方法都是线程安全的,因此在修改字符串时需要进行额外的同步操作,导致性能稍低。
StringBuilder的方法没有添加同步操作,因此在单线程环境下可直接进行更快的操作。
 

使用场景

如果需要进行多线程环境下的字符串操作,或者关注线程安全性,应使用StringBuffer,它能保证数据的一致性,适用于并发操作或共享对象的场景。
如果在
单线程环境下进行字符串操作,并且需要更好的性能,可以选择使用StringBuilder,它没有同步开销,并且适用于在单线程环境中构建和修改字符串。


总结起来,StringBuffer适用于多线程或需要线程安全的场景,而StringBuilder适用于单线程、性能要求高的场景。在大多数情况下,如果没有线程安全的要求,推荐使用StringBuilder,因为它的性能更高。

3.为什么在频繁字符串拼接或修改的情况下,使用StringBuilder比使用String更高效?

可变性: StringBuilder是可变的,而String是不可变的。当我们对一个已有的字符串进行拼接或修改时,String会创建一个新的字符串对象,而原来的字符串对象保持不变。这意味着每次拼接或修改都会生成一个新的字符串对象,导致频繁的对象创建和销毁,造成内存和性能的浪费。相反,StringBuilder可以在一个可变的字符串缓冲区中进行修改,避免了创建新对象的开销。

性能优化: StringBuilder在内部使用一个可扩展的字符数组(char[])来存储字符串数据。它会动态调整容量以适应拼接操作的需要,避免了频繁地重新分配内存空间的开销。相比之下,String每次进行拼接或修改时都需要创建一个新的字符串对象,内存分配和复制的开销较大。

性能统一: 当使用StringBuilder进行频繁的拼接和修改时,所有的操作都是在同一个对象上进行的,没有额外的对象创建和销毁。这种一致性可以提高性能,特别是在循环或大量字符串拼接的场景下,显著减少了内存管理和垃圾回收的压力。

注意:尽管StringBuilder在大多数情况下比String更高效,但也需要根据具体的需求和应用场景来选择。如果在多线程环境下进行字符串操作或需要线程安全性,应选择StringBuffer;如果在单线程环境下进行字符串操作,并且关注性能,StringBuilder是更好的选择。对于简单的字符串拼接,使用String的加号操作符(+)也足够高效。最佳选择取决于具体的使用情况和性能需求。

小贴士:

当StringBuilder的内部字符数组(char[])容量不足以容纳新的字符时,它会自动进行扩容以适应更多的字符。

以下是一个使用StringBuilder进行字符串拼接,并展示其扩容机制的简单示例代码:

package com.xw.framework;

public class test {
public static void main(String[] args) {
	StringBuilder sb = new StringBuilder();
	System.out.println("初始容量:" + sb.capacity());

	// 拼接字符
	for (int i = 1; i <= 20; i++) {
	    sb.append("Char").append(i).append(" ");
	    System.out.println("当前容量:" + sb.capacity());
	}

	String result = sb.toString();
	System.out.println("最终结果:" + result);
}
}

输出示例:

在本示例中:

  • StringBuilder对象初始容量为16。
  • 每次拼接新字符时,如果当前容量不足以容纳该字符,StringBuilder会扩容。通常情况下,扩容会将当前容量加倍。但并不是每次都会扩容,仅在实际需要时进行。
  • 逐步拼接字符后,容量依次增加。可以观察到容量分别为16、34、70、142。在原有的基础多加一倍并多出两个,(16*2)+2=34 ....(34*2)+2=70....(70*2)+2=142.....
  • 最终结果是拼接了20个字符的字符串。

4.如何选择String、StringBuffer和StringBuilder之间的适当类型?

  1. 线程安全性要求 如果需要在多线程环境下进行字符串操作,或者需要保证线程安全性,应选择 StringBufferStringBuffer 的方法是线程安全的,使用了同步操作,确保多个线程可以安全地访问和修改同一个对象。但是这也会带来一些性能开销。

    如果在单线程环境下操作字符串,或者不需要考虑线程安全性,可以选择 StringBuilder 或 String
  2. 性能需求 String 是不可变的,每次修改字符串都会创建一个新的字符串对象,因此在频繁的字符串拼接或修改操作中,性能较低。如果性能是一个关键因素,应该优先选择 StringBuilder

    • StringBuilder 是可变的,并且没有同步开销,适用于频繁的字符串拼接和修改操作。
    • StringBuffer 也可以用于频繁的字符串操作,但由于它是线程安全的,每个方法都进行了同步,可能性能略低于 StringBuilder
  3. 初始化大小和预计字符串长度 如果知道字符串的大概长度或预计的字符数量,可以考虑初始化 StringBuilder 或 StringBuffer 的初始容量,以避免不必要的扩容操作。

综合考虑以上因素,可以根据实际需求进行选择:

  • 如果需要线程安全性或在多线程环境下进行字符串操作,选择 StringBuffer
  • 如果在单线程环境下进行频繁的字符串拼接或修改操作,并且不需要线程安全性,选择 StringBuilder 可以获得更好的性能。
  • 如果字符串是常量或只需进行少量拼接操作,并且不需要修改字符串内容,直接使用 String 即可。

需要根据具体的场景和需求选择合适的类型,以获得最佳的性能和功能。

希望这篇博客可以帮助你了解String、StringBuffer和StringBuilder的区别以及使用场景!!

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

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

相关文章

Flink入门学习(一)

Flink 1. 概述 分布式、高性能、随时可用以及准确的流处理应用程序打造的开源流处理框架&#xff0c;用于对无界和有界数据流进行有状态计算。Flink 被设计在所有常见的集群环境中运行&#xff0c;以内存执行速度和任意规模来执行计算。 有界流&#xff1a;有定义流的开始&am…

Vue实例挂载的过程

一、思考与分析 我们都听过知其然知其所以然这句话 那么不知道是否思考过new Vue()这个过程中究竟做了些什么&#xff1f; 过程中是如何完成数据的绑定&#xff0c;又是如何将数据渲染到视图的等等 首先找到vue的构造函数 源码位置&#xff1a;src\core\instance\index.js…

高性能计算详细的自学方法及路线,强烈建议收藏!

一. 本文纲要 细想一下&#xff0c;其实无论是要自学高性能计算&#xff0c;还是要自学开车&#xff0c;无论我们要自学什么&#xff0c;都要弄明白以下几个问题&#xff1a;我们适不适合自学&#xff0c;怎么自学&#xff0c;从哪开始自学&#xff0c;自学到什么程度&#xff…

如何使用二维码实现业务流程闭环管理?

在日常工作中有许多业务流程需要进行跟踪记录&#xff0c;以确保掌握当前进度&#xff0c;譬如隐患上报整改、业务申请办理进度等&#xff0c;这时就可以应用二维码来实现业务流程的闭环管理。 通过草料二维码平台提供的表单功能&#xff0c;可以扫码提交表单记录&#xff0c;…

java之路 —— Shiro与Springboot整合开发

文章目录 前言一、基本开发步骤二、Springboot整合开发三、Shiro的集成四、测试 前言 在 Spring Boot 中做权限管理&#xff0c;一般来说&#xff0c;主流的方案是 Spring Security &#xff0c;但是&#xff0c;仅仅从技术角度来说&#xff0c;也可以使用 Shiro。 在 Spring…

MyBatisPlus基础功能使用

文章目录 MyBatisPlus基础功能CRUDBaseMapperServiceImpl 条件构造器注解一对多、多对一映射 MyBatisPlus基础功能 CRUD BaseMapper BaseMapper 接口是 MyBatis-Plus 提供的一个基础 Mapper 接口&#xff0c;它定义了一系列的通用数据库操作方法&#xff0c;包括插入、更新、…

项目——学生信息管理系统7

目录 学生选课功能的介绍 把 课程的数据库表创建出来 创建实体类 创建添加课程页面 AddCourseFrm&#xff0c;注意创建成JInternalFrame类型 页面制作&#xff0c;具体参照之前的 回到 MainFrm 添加课程管理菜单项 给添加课程按钮绑定事件 回到AddCourseFrm 页面 1. 把…

JSON百科全书:学习JSON看这一篇就够了

目录 1.1 JSON 简介 1.1.1 什么是 JSON 1.1.2 JSON 的特点 1.2 JSON 语法 1.2.1 JSON 键/值对 1.2.2 JSON 字符串 1.2.3 JSON 数值 1.2.4 JSON 对象 1.2.5 JSON 数组 1.2.6 JSON 布尔值 1.2.7 JSON null 1.2.8 JSON 文件 1.3 JSON 对象 1.3.1 访问对象的值 1.3…

7DGroup性能实施项目日记7

九月廿五 壬寅年 虎 庚戌月 丙午日 从昨天的场景执行和结果分析来看&#xff0c;效果有一些。今天我们又换了一个接口&#xff0c;看看有什么新问题。 从我的 RESAR 性能工程的逻辑上来看&#xff0c;现在是在基准场景执行的阶段。在这个阶段就是要把每个接口都单独压到最大tp…

大数据开发之Hive案例篇14:某个节点HDFS块比较多

文章目录 一. 问题描述二. 解决方案2.1 查看节点安装的组件2.2 排查HDFS配置2.3 排查Yarn配置2.3.1 首先查看下nodemanager的日志2.3.2 查看container分配情况2.3.3 查看调度机制2.3.4 查看集群任务情况2.3.5 集群负载情况2.3.6 resourcemanager与nodemanager是否可以混合部署 …

基于Springboot的在线竞拍系统(拍卖系统)

今天给大家带来了一个在线竞拍(拍卖)系统&#xff08;带设计报告&#xff09;&#xff0c;项目功能完善。 用户功能 包括沙箱支付宝支付&#xff0c;在线竞拍&#xff0c;收藏管理&#xff0c;个人资料管理&#xff0c;竞拍管理等等。 机构功能 包括&#xff0c;上传竞拍项目…

springboot球赛管理小程序

球赛管理系统 springboot球赛管理系统小程序 java球赛管理小程序 技术&#xff1a; 基于springbootvue小程序球赛管理系统的设计与实现 运行环境&#xff1a; JAVA版本&#xff1a;JDK1.8 IDE类型&#xff1a;IDEA、Eclipse都可运行 数据库类型&#xff1a;MySql&#xff08;…

优盘无法识别?恢复U盘数据就这样做!

到底是怎么回事呢&#xff1f;我的优盘用得好好的&#xff0c;突然就无法识别了。优盘里有对我很重要的数据&#xff0c;这些数据还能找回来吗&#xff1f;希望大家帮帮我&#xff01; 优盘作为常用的便携式存储设备。为我们随时随地保存数据提供了很大的便利。我们可以利用u盘…

C++并发编程之玩转condition_variable

C并发编程之玩转condition_variable 0.导语 最近在看并发编程相关的代码&#xff0c;自己顺手从0开始写了个小项目玩转并发场景下的生产消费者模型&#xff0c;如果你想提高多线程编程方面的能力&#xff0c;想熟练掌握condition_variable的使用&#xff0c;甚至想在面试当中凸…

Go 语言精进之路——Go 中常见并发模式总结

文章目录 前言创建模式退出模式分离模式join 模式notify-and-wait模式退出模式的应用 管道模式扇出与扇入模式 超时与取消模式 前言 在语言层面&#xff0c;Go针对CSP模型提供了三种并发原语。 goroutine&#xff1a;对应CSP模型中的P&#xff0c;封装了数据的处理逻辑&#x…

数字化赋能大健康实体行业迈入发展新阶段,大健康招商加盟系统优势有哪些?

数字经济的发展&#xff0c;正推动大健康实体行业迈入高质量发展新阶段。大健康实体行业应如何在数字化浪潮中抢占先机&#xff1f;大健康实体行业招商加盟平台应如何开发设计&#xff0c;才能帮助大健康企业主取得营收突破&#xff1f; 围绕蚓链大健康招商加盟系统&#xff0c…

ppt制作相关内容小结

ppt制作是天大的事&#xff01;是讲清一件事&#xff0c;表达自己的最好方式 1.删除ppt中的所有备注信息2.ppt制作中的快捷键3.精美的ppt收集 这里还是要提醒自己一下&#xff0c;做好ppt是外在的事情&#xff0c;把道理吃透才是根本&#xff01; 但是ppt外在也是表达的一种方式…

闭包实现函数柯里化,js实现

闭包实现函数柯里化&#xff0c;js实现 函数柯里化定义代码实现 函数柯里化定义 柯里化&#xff08;Currying&#xff09;是把接受多个参数的函数变换成接受一个单一参数(最初函数的第一个参数)的函数&#xff0c;并且返回接受余下的参数且返回结果的新函数的技术 即函数可以接…

.NET 8 Preview 4 中的 ASP.NET Core 更新

作者&#xff1a;Daniel Roth - Principal Program Manager, ASP.NET 翻译&#xff1a;Alan Wang 排版&#xff1a;Alan Wang .NET 8 Preview 4 现已可用&#xff0c;并包括了许多对 ASP.NET Core 的新改进。 以下是本预览版本中的新内容摘要&#xff1a; Blazor 使用 Blazor …

图片:前端展示图像(img 、picture、svg、canvas )及常用图片格式(PNG、JPG、JPEG、WebP、GIF、SVG、AVIF等)

一、浏览器网页展示图片方法 1.1、HTML <img> 标签 <!DOCTYPE html> <html><head><title>图片展示</title></head><body><h1>图片展示</h1><img src"example.jpg" alt"Example Image" w…