下雨天读源码——String、StringBuilder、StringBuffer

2024-02-07 14:20

本文主要是介绍下雨天读源码——String、StringBuilder、StringBuffer,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

下雨天读源码——String、StringBuilder、StringBuffer

String源码

类定义

public final class String implements java.io.Serializable, Comparable<String>, CharSequence 

​ 这是string源码的类定义,首先是一个final类型的不可变类型,其次string实现了可比较、可序列化接口,主要说一下为什么是final的吧。这是顶级大佬设计string时的智慧啊,我们知道java中有一个string的常量池,在这个池中的对象可以被多个引用指向,如果string是可变的话,当一个引用修改了string,那么其他的引用的值也会发生变化,后果将是灾难性的,这是一个方面的考虑。

在这里插入图片描述

内置属性有四个

	private final char value[];/** Cache the hash code for the string */private int hash; // Default to 0/** use serialVersionUID from JDK 1.0.2 for interoperability */private static final long serialVersionUID = -6849794470754667710L;/*** Class String is special cased within the Serialization Stream Protocol.** A String instance is written into an ObjectOutputStream according to* <a href="{@docRoot}/../platform/serialization/spec/output.html">* Object Serialization Specification, Section 6.2, "Stream Elements"</a>*/private static final ObjectStreamField[] serialPersistentFields =new ObjectStreamField[0];

String的大部分方法都是围绕着对value[]进行操作的。

构造方法

无参构造方法
public String() {this.value = "".value;}

可以看出string的无参构造是一个空字符串。

 	String str = new String();if (str != null){System.out.println("str is not null!");}if (str.isEmpty()){System.out.println("str is empty");}
------------------------------------------------------------
str is not null!
str is empty

有参构造

string的有参构造就太多了!拿几个典型的例子来看。

//用一个字符串生成一个字符串
public String(String original) {this.value = original.value;this.hash = original.hash;}//将一个字符数组生成为一个字符串
public String(char value[]) {this.value = Arrays.copyOf(value, value.length);}//将一个字符数组中的一段生成为字符串
public String(char value[], int offset, int count)public String(int[] codePoints, int offset, int count)

常见方法

常见方法我们一个一个来看。(部分没有坚持读下去,朋友叫打游戏去了)

	   //定义一个字符串,我们可以点出来以下这些方法,眼熟的一些方法已罗列在下。String str = new String();str.length();str.getBytes(StandardCharsets.UTF_8);str.equals();str.isEmpty();str.getBytes();str.toUpperCase(Locale.ROOT);str.toLowerCase(Locale.ROOT);str.trim();str.intern();str.contains();str.split();str.toCharArray();str.charAt();str.substring();str.replace();str.codePointAt();str.compareTo();str.concat();str.contentEquals();str.endsWith();str.indexOf();str.lastIndexOf();str.matches();str.replaceAll();str.replaceFirst();
str.length();

返回string对象里面的char数组长度

public int length() {return value.length;
}

str.getBytes(StandardCharsets.UTF_8);

按照编码返回一个字节数组。

public byte[] getBytes(Charset charset) {if (charset == null) throw new NullPointerException();return StringCoding.encode(charset, value, 0, value.length);}

str.equals();
public boolean equals(Object anObject) {if (this == anObject) {return true;}if (anObject instanceof String) {String anotherString = (String)anObject;int n = value.length;if (n == anotherString.value.length) {char v1[] = value;char v2[] = anotherString.value;int i = 0;while (n-- != 0) {if (v1[i] != v2[i])return false;i++;}return true;}}return false;}

str.isEmpty()

判断string内置char数组的长度是否为0来判断是否为空

public boolean isEmpty() {return value.length == 0;}

str.toUpperCase(Locale.ROOT)

将字母转为大写

str.toLowerCase(Locale.ROOT)

将字母转为小写

str.trim()

去除字符首位的空格,准确来说,是自动截断ASCII码<=32位的所有字符,然后头尾截断整个字符串。

public String trim() {int len = value.length;int st = 0;char[] val = value;    /* avoid getfield opcode *///可显示字符的ASCII码是从32-126的,第32正好是空格。while ((st < len) && (val[st] <= ' ')) {st++;}while ((st < len) && (val[len - 1] <= ' ')) {len--;}return ((st > 0) || (len < value.length)) ? substring(st, len) : this;}

str.substring()

从[beginIndex,endIndex]这个区间截断字符串,如果截取的字符串跟原字符串一样,没有发生改变,则返回原字符串;如果发生了改变,则通过调用构造方法
public String(char value[], int offset, int count),生成一个新字符串。

public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > value.length) {throw new StringIndexOutOfBoundsException(endIndex);}int subLen = endIndex - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);}

str.contains();
public boolean contains(CharSequence s) {return indexOf(s.toString()) > -1;}

str.indexOf();
static int indexOf(char[] source, int sourceOffset, int sourceCount,char[] target, int targetOffset, int targetCount,int fromIndex) {//先做异常处理if (fromIndex >= sourceCount) {return (targetCount == 0 ? sourceCount : -1);}if (fromIndex < 0) {fromIndex = 0;}//如果空字符串出现了,就返回空字符串出现在当前字符串的第0位//       String str = new String();//       String source = "abc";//       System.out.println(source.indexOf(str)); 输出0if (targetCount == 0) {return fromIndex;}char first = target[targetOffset];int max = sourceOffset + (sourceCount - targetCount);for (int i = sourceOffset + fromIndex; i <= max; i++) {/* Look for first character. */if (source[i] != first) {while (++i <= max && source[i] != first);}/* Found first character, now look at the rest of v2 */if (i <= max) {int j = i + 1;int end = j + targetCount - 1;for (int k = targetOffset + 1; j < end && source[j]== target[k]; j++, k++);if (j == end) {/* Found whole string. */return i - sourceOffset;}}}return -1;}
//妙啊,刚开始理解先不要管偏移量的事情,当做sourceoffset=0,targetoffset=0;

str.split();

这个源码有点复杂,暂时没时间整明白。

public String[] split(String regex, int limit) {/* fastpath if the regex is a(1)one-char String and this character is not one of theRegEx's meta characters ".$|()[{^?*+\\", or(2)two-char String and the first char is the backslash andthe second is not the ascii digit or ascii letter.*/char ch = 0;if (((regex.value.length == 1 &&".$|()[{^?*+\\".indexOf(ch = regex.charAt(0)) == -1) ||(regex.length() == 2 &&regex.charAt(0) == '\\' &&(((ch = regex.charAt(1))-'0')|('9'-ch)) < 0 &&((ch-'a')|('z'-ch)) < 0 &&((ch-'A')|('Z'-ch)) < 0)) &&(ch < Character.MIN_HIGH_SURROGATE ||ch > Character.MAX_LOW_SURROGATE)){int off = 0;int next = 0;boolean limited = limit > 0;ArrayList<String> list = new ArrayList<>();//indexof找到当前字符串中匹配上的字符后,将next指针指向该位置while ((next = indexOf(ch, off)) != -1) {if (!limited || list.size() < limit - 1) {list.add(substring(off, next));off = next + 1;} else {    // last one//assert (list.size() == limit - 1);list.add(substring(off, value.length));off = value.length;break;}}// If no match was found, return thisif (off == 0)return new String[]{this};// Add remaining segmentif (!limited || list.size() < limit)list.add(substring(off, value.length));// Construct resultint resultSize = list.size();if (limit == 0) {while (resultSize > 0 && list.get(resultSize - 1).length() == 0) {resultSize--;}}String[] result = new String[resultSize];return list.subList(0, resultSize).toArray(result);}return Pattern.compile(regex).split(this, limit);}

str.toCharArray();

底层调用的是native方法

 public char[] toCharArray() {// Cannot use Arrays.copyOf because of class initialization order issueschar result[] = new char[value.length];System.arraycopy(value, 0, result, 0, value.length);return result;}

str.charAt();

返回value数组中的第index元素

public char charAt(int index) {if ((index < 0) || (index >= value.length)) {throw new StringIndexOutOfBoundsException(index);}return value[index];}

str.getChars()

将此字符串中的字符复制到目标字符数组中。

要复制的第一个字符位于索引srcbegin处;要复制的最后一个字符位于索引srcEnd-1处(因此要复制的字符总数为srcEnd-srcebeng)。将字符复制到dst的子阵列中,从索引dst开始,到索引dst结束:

DSTBENG+(srcEnd SRCBENG)-1

参数:

srcbeagin–要复制的字符串中第一个字符的索引。

srcEnd–要复制的字符串中最后一个字符后的索引。

dst–目标阵列。

DSTBENG–目标阵列中的起始偏移量。

public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {if (srcBegin < 0) {throw new StringIndexOutOfBoundsException(srcBegin);}if (srcEnd > value.length) {throw new StringIndexOutOfBoundsException(srcEnd);}if (srcBegin > srcEnd) {throw new StringIndexOutOfBoundsException(srcEnd - srcBegin);}System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);}

str.substring();

如果不是按原字符串截断,那么会重新生成一个新的string对象

public String substring(int beginIndex, int endIndex) {if (beginIndex < 0) {throw new StringIndexOutOfBoundsException(beginIndex);}if (endIndex > value.length) {throw new StringIndexOutOfBoundsException(endIndex);}int subLen = endIndex - beginIndex;if (subLen < 0) {throw new StringIndexOutOfBoundsException(subLen);}return ((beginIndex == 0) && (endIndex == value.length)) ? this: new String(value, beginIndex, subLen);}

str.replace();
用指定的文字替换序列替换与文字目标序列匹配的此字符串的每个子字符串。替换从字符串的开头一直进行到结尾,例如,将字符串“aaa”中的“aa”替换为“b”将导致“ba”而不是“ab”。参数:target–要替换的字符值序列替换–字符值的替换顺序返回:结果字符串
str.intern();

具体intern用法其实很简单,就是字符串调用intern方法后,就会将字符串注册到常量池中,jdk1.7之前是直接拷贝内容,jdk1.7之后是在常量池中建立一个引用指向字符串在堆内的地址。

返回字符串对象的规范表示形式。最初为空的字符串池由类字符串私下维护。调用intern方法时,如果池中已经包含一个字符串,该字符串等于equals(object)方法确定的该字符串对象,则返回池中的字符串。否则,此字符串对象将添加到池中,并返回对此字符串对象的引用。因此,对于任意两个字符串s和t,s.intern()==t.intern()为真当且仅当s.equals(t)为真时。所有文字字符串和字符串值常量表达式都被插入。字符串文本在Java的第3.10.5节中定义™ 语言规范。返回:与此字符串具有相同内容,但保证来自唯一字符串池的字符串
str.concat();

主要是用来拼接两个字符串。

public String concat(String str){int otherLen = str.length();if(otherLen == 0){return this;}int len = value.length;char buf[] = Arrays.copyOf(value,len+otherLen);//将传入字符串从0的位置开始复制到扩展后的字符串,从原字符串长度的位置开始复制,复制的元素个数为传入字符穿的长度str.getChars(buf,len);return new String(buf,true);
}

string源码一共3000行(带注释),同时也是java程序里面比较简单的源码,阅读源码有助于提高我们对java整个面向对象、面向接口程序设计思想的理解。


StringBuilder源码

StringBuilder源码带注释一共439行,工作量比较小,读起来也稍微快一点。

StringBuilder类的说明

可变的字符序列。此类提供与StringBuffer兼容的API,但不保证同步。此类被设计为在单个线程使用字符串缓冲区的地方(通常情况下)作为StringBuffer的插入式替换。在可能的情况下,建议优先使用该类而不是StringBuffer,因为在大多数实现中它会更快。StringBuilder上的主要操作是append和insert方法,它们重载以接受任何类型的数据。每个都有效地将给定的数据转换为字符串,然后将该字符串的字符追加或插入到字符串生成器中。append方法总是在生成器的末尾添加这些字符;insert方法在指定点添加字符。例如,如果z引用当前内容为“start”的字符串生成器对象,那么方法调用z.append(“le”)会导致字符串生成器包含“startle”,而z.insert(4,“le”)会将字符串生成器更改为包含“starlet”。通常,如果sb引用StringBuilder的实例,那么sb.append(x)与sb.insert(sb.length(),x)具有相同的效果。每个字符串生成器都有一个容量。只要字符串生成器中包含的字符序列的长度不超过容量,就不需要分配新的内部缓冲区。如果内部缓冲区溢出,它会自动变大。多线程使用StringBuilder实例不安全。如果需要这种同步,建议使用StringBuffer。除非另有说明,否则将null参数传递给此类中的构造函数或方法将导致引发NullPointerException。

总结如下:

1.线程不安全

2.用来做string类型的数据的插入与拼接

3.性能上最快

public final class StringBuilderextends AbstractStringBuilderimplements java.io.Serializable, CharSequence

属性

继承自抽象父类的属性有两个

//The value is used for character storage.	char[] value;/*** The count is the number of characters used.*/int count;

构造方法

无参构造
public StringBuilder() {super(16);} 
//默认构造方法是创建一个容量为16的字符数组大小。//父类的构造方法
AbstractStringBuilder(int capacity) {value = new char[capacity];}
有参构造
//将一个字符串作为参数传给构造器,会构建一个str.length() + 16空字符数组,然后将str的值赋给数组中去。
public StringBuilder(String str) {super(str.length() + 16);append(str);}

主要方法

append
@Overridepublic StringBuilder append(Object obj) {return append(String.valueOf(obj));}@Overridepublic StringBuilder append(String str) {super.append(str);return this;}public StringBuilder append(StringBuffer sb) {super.append(sb);return this;}@Overridepublic StringBuilder append(CharSequence s) {super.append(s);return this;}@Overridepublic StringBuilder append(CharSequence s, int start, int end) {super.append(s, start, end);return this;}@Overridepublic StringBuilder append(char[] str) {super.append(str);return this;}@Overridepublic StringBuilder append(char[] str, int offset, int len) {super.append(str, offset, len);return this;}@Overridepublic StringBuilder append(boolean b) {super.append(b);return this;}@Overridepublic StringBuilder append(char c) {super.append(c);return this;}@Overridepublic StringBuilder append(int i) {super.append(i);return this;}@Overridepublic StringBuilder append(long lng) {super.append(lng);return this;}@Overridepublic StringBuilder append(float f) {super.append(f);return this;}@Overridepublic StringBuilder append(double d) {super.append(d);return this;}

可以看出append方法由13种重构,万物皆可append。

选择其中最尝试用的字符串拼接为例,继续往下点,到父类的append方法。

public AbstractStringBuilder append(String str) {if (str == null)return appendNull();int len = str.length();ensureCapacityInternal(count + len);str.getChars(0, len, value, count);count += len;return this;}//判断拼接以后的数组长度是否会超过value的长度,如果超过,会调用自己的扩容方法来动态的扩容。
private void ensureCapacityInternal(int minimumCapacity) {// overflow-conscious codeif (minimumCapacity - value.length > 0) {value = Arrays.copyOf(value,newCapacity(minimumCapacity));}}//扩容方法,先将当前value的数组长度*2+2,再与传进来的长度进行比较,如果仍然小于要求的长度,那干脆直接使用传进来的长度,再判断是否超出整数的最大长度,如果超出则溢出为负数,那么就抛出异常,否则就扩容成功。
private int newCapacity(int minCapacity) {// overflow-conscious codeint newCapacity = (value.length << 1) + 2;if (newCapacity - minCapacity < 0) {newCapacity = minCapacity;}return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)? hugeCapacity(minCapacity): newCapacity;}private int hugeCapacity(int minCapacity) {if (Integer.MAX_VALUE - minCapacity < 0) { // overflowthrow new OutOfMemoryError();}return (minCapacity > MAX_ARRAY_SIZE)? minCapacity : MAX_ARRAY_SIZE;}

就到了AbstractStringBuilder的append方法中,在这个方法中又调用了str.getChars()方法,上面提到过,底层还是调用的copyof方法。

insert方法

实现方式跟append一样,只不过在细节上有所区别,它需要一个精确的位置来决定将字符串插入到哪一个位置。

public AbstractStringBuilder insert(int index, char[] str, int offset,int len){if ((index < 0) || (index > length()))throw new StringIndexOutOfBoundsException(index);if ((offset < 0) || (len < 0) || (offset > str.length - len))throw new StringIndexOutOfBoundsException("offset " + offset + ", len " + len + ", str.length "+ str.length);ensureCapacityInternal(count + len);System.arraycopy(value, index, value, index + len, count - index);System.arraycopy(str, offset, value, index, len);count += len;return this;}

StringBuffer源码

首先是类声明,StringBuffer与StringBuilder是继承自同一个父类,本是同根生,性能小差距!

public final class StringBufferextends AbstractStringBuilderimplements java.io.Serializable, CharSequence

stringbuffer支持多线程

区别在于stringbuffer的方法都加了锁(构造方法除外),属实是为了多线程而设计的啊。

@Overridepublic synchronized StringBuffer append(Object obj) {toStringCache = null;super.append(String.valueOf(obj));return this;}@Overridepublic synchronized StringBuffer append(String str) {toStringCache = null;super.append(str);return this;}public synchronized StringBuffer append(StringBuffer sb) {toStringCache = null;super.append(sb);return this;}/*** @since 1.8*/@Overridesynchronized StringBuffer append(AbstractStringBuilder asb) {toStringCache = null;super.append(asb);return this;}@Overridepublic synchronized StringBuffer append(CharSequence s) {toStringCache = null;super.append(s);return this;}/*** @throws IndexOutOfBoundsException {@inheritDoc}* @since      1.5*/@Overridepublic synchronized StringBuffer append(CharSequence s, int start, int end){toStringCache = null;super.append(s, start, end);return this;}@Overridepublic synchronized StringBuffer append(char[] str) {toStringCache = null;super.append(str);return this;}/*** @throws IndexOutOfBoundsException {@inheritDoc}*/@Overridepublic synchronized StringBuffer append(char[] str, int offset, int len) {toStringCache = null;super.append(str, offset, len);return this;}@Overridepublic synchronized StringBuffer append(boolean b) {toStringCache = null;super.append(b);return this;}@Overridepublic synchronized StringBuffer append(char c) {toStringCache = null;super.append(c);return this;}@Overridepublic synchronized StringBuffer append(int i) {toStringCache = null;super.append(i);return this;}

具体方法实现呢,参看它父类的实现,跟stringbuilder一样一样儿的。

Stringbuffer整了点花活

在属性上比其兄弟多了一条toStringCache,用来存储tostring的返回值,这样在返回的时候会快上一些嘛?还有就是当调用append方法时,stringbuffer对象发生改变,就会将这个缓存清空,这也许也是stringbuffer不如stringbuilder的原因吧。

private transient char[] toStringCache;

toString方法

@Overridepublic synchronized String toString() {if (toStringCache == null) {toStringCache = Arrays.copyOfRange(value, 0, count);}return new String(toStringCache, true);}

三者之间的比较

字符串拼接时的性能比较

三者是string < stringbuffer < stringbuilder,实际上stringbuffer与stringbuilder的性能十分接近(单线程下),请看测试用例

/*** @Description:* @ClassName: Test* @Author: yokna* @Date: 2021/8/9 14:17* @Version: 1.0*/
public class Test {public static void main(String[] args) {//string原生的concat方法long beginTime = System.currentTimeMillis();String str1 = "hello";String str2 = "nihao";for (int i = 0; i < 100000; i++) {str1 = str1+str2;}long endTime = System.currentTimeMillis();System.out.println("String:"+(endTime-beginTime));long beginTime1 = System.currentTimeMillis();StringBuffer sb1 = new StringBuffer("hello");StringBuffer sb2 = new StringBuffer();for (int i = 0; i < 100000; i++) {sb1.append(sb2);}long endTime1 = System.currentTimeMillis();System.out.println("StringBuffer:"+(endTime1-beginTime1));long beginTime2 = System.currentTimeMillis();StringBuilder stringBuilder1 = new StringBuilder("hello");StringBuilder stringBuilder2 = new StringBuilder("nihao");for (int i = 0; i < 100000; i++) {stringBuilder1.append(stringBuilder2);}long endTime2 = System.currentTimeMillis();System.out.println("StringBuilder:"+(endTime2-beginTime2));}
}--------------------------------------------------
String:19207
StringBuffer:3
StringBuilder:4

在这场小范围的火拼这种,StringBuffer取巧获得了胜利,看上去似乎其性能还优于StringBuilder,然而是不是一直如此呢?
下面开始StringBuffer与StringBuilder的皇城pk,当我们将量级从10w改为1000w时,差距就显现出来了!

/*** @Description:* @ClassName: Test* @Author: yokna* @Date: 2021/8/9 14:17* @Version: 1.0*/
public class Test {public static void main(String[] args) {long beginTime1 = System.currentTimeMillis();StringBuffer sb1 = new StringBuffer("hello");StringBuffer sb2 = new StringBuffer();for (int i = 0; i < 10000000; i++) {sb1.append(sb2);}long endTime1 = System.currentTimeMillis();System.out.println("StringBuffer:"+(endTime1-beginTime1));long beginTime2 = System.currentTimeMillis();StringBuilder stringBuilder1 = new StringBuilder("hello");StringBuilder stringBuilder2 = new StringBuilder("nihao");for (int i = 0; i < 10000000; i++) {stringBuilder1.append(stringBuilder2);}long endTime2 = System.currentTimeMillis();System.out.println("StringBuilder:"+(endTime2-beginTime2));}
}
StringBuffer:640
StringBuilder:206

总结

​ 三者之间的差距确实有,可以看出String原生的字符串相加不仅费时间还费空间(没有看空间耗费情况,仅凭直觉,这句话虽然正确但是不太严谨),但StringBuffer与StringBuilder之间性能差不多。
StringBuffer第一次获胜的原因可能是他在程序执行过程中,刚好一个时间片内就执行完了,不涉及到线程之间上下文的切换,而它兄弟可能就比较惨,在执行过程中被打断的次数比较多吧。
第二次StringBuffer败北的原因在于其append方法加了synchronized关键字修饰,锁住了整个方法,在单线程下仍然会有获取锁的一个过程,且StringBuffer每一次append时都会对toStringCache清空一次,也会有额外的开销。但是这些代价是值得的,它的这些设计,让它能胜任其兄弟无法胜任的工作,那就是肩负多线程环境下的string操作。

总而言之,言而总之,遇事不决,StringBuffer!

这篇关于下雨天读源码——String、StringBuilder、StringBuffer的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/687997

相关文章

JAVA智听未来一站式有声阅读平台听书系统小程序源码

智听未来,一站式有声阅读平台听书系统 🌟&nbsp;开篇:遇见未来,从“智听”开始 在这个快节奏的时代,你是否渴望在忙碌的间隙,找到一片属于自己的宁静角落?是否梦想着能随时随地,沉浸在知识的海洋,或是故事的奇幻世界里?今天,就让我带你一起探索“智听未来”——这一站式有声阅读平台听书系统,它正悄悄改变着我们的阅读方式,让未来触手可及! 📚&nbsp;第一站:海量资源,应有尽有 走进“智听

Java ArrayList扩容机制 (源码解读)

结论:初始长度为10,若所需长度小于1.5倍原长度,则按照1.5倍扩容。若不够用则按照所需长度扩容。 一. 明确类内部重要变量含义         1:数组默认长度         2:这是一个共享的空数组实例,用于明确创建长度为0时的ArrayList ,比如通过 new ArrayList<>(0),ArrayList 内部的数组 elementData 会指向这个 EMPTY_EL

如何在Visual Studio中调试.NET源码

今天偶然在看别人代码时,发现在他的代码里使用了Any判断List<T>是否为空。 我一般的做法是先判断是否为null,再判断Count。 看了一下Count的源码如下: 1 [__DynamicallyInvokable]2 public int Count3 {4 [__DynamicallyInvokable]5 get

工厂ERP管理系统实现源码(JAVA)

工厂进销存管理系统是一个集采购管理、仓库管理、生产管理和销售管理于一体的综合解决方案。该系统旨在帮助企业优化流程、提高效率、降低成本,并实时掌握各环节的运营状况。 在采购管理方面,系统能够处理采购订单、供应商管理和采购入库等流程,确保采购过程的透明和高效。仓库管理方面,实现库存的精准管理,包括入库、出库、盘点等操作,确保库存数据的准确性和实时性。 生产管理模块则涵盖了生产计划制定、物料需求计划、

Spring 源码解读:自定义实现Bean定义的注册与解析

引言 在Spring框架中,Bean的注册与解析是整个依赖注入流程的核心步骤。通过Bean定义,Spring容器知道如何创建、配置和管理每个Bean实例。本篇文章将通过实现一个简化版的Bean定义注册与解析机制,帮助你理解Spring框架背后的设计逻辑。我们还将对比Spring中的BeanDefinition和BeanDefinitionRegistry,以全面掌握Bean注册和解析的核心原理。

音视频入门基础:WAV专题(10)——FFmpeg源码中计算WAV音频文件每个packet的pts、dts的实现

一、引言 从文章《音视频入门基础:WAV专题(6)——通过FFprobe显示WAV音频文件每个数据包的信息》中我们可以知道,通过FFprobe命令可以打印WAV音频文件每个packet(也称为数据包或多媒体包)的信息,这些信息包含该packet的pts、dts: 打印出来的“pts”实际是AVPacket结构体中的成员变量pts,是以AVStream->time_base为单位的显

kubelet组件的启动流程源码分析

概述 摘要: 本文将总结kubelet的作用以及原理,在有一定基础认识的前提下,通过阅读kubelet源码,对kubelet组件的启动流程进行分析。 正文 kubelet的作用 这里对kubelet的作用做一个简单总结。 节点管理 节点的注册 节点状态更新 容器管理(pod生命周期管理) 监听apiserver的容器事件 容器的创建、删除(CRI) 容器的网络的创建与删除

red5-server源码

red5-server源码:https://github.com/Red5/red5-server

TL-Tomcat中长连接的底层源码原理实现

长连接:浏览器告诉tomcat不要将请求关掉。  如果不是长连接,tomcat响应后会告诉浏览器把这个连接关掉。    tomcat中有一个缓冲区  如果发送大批量数据后 又不处理  那么会堆积缓冲区 后面的请求会越来越慢。

Windows环境利用VS2022编译 libvpx 源码教程

libvpx libvpx 是一个开源的视频编码库,由 WebM 项目开发和维护,专门用于 VP8 和 VP9 视频编码格式的编解码处理。它支持高质量的视频压缩,广泛应用于视频会议、在线教育、视频直播服务等多种场景中。libvpx 的特点包括跨平台兼容性、硬件加速支持以及灵活的接口设计,使其可以轻松集成到各种应用程序中。 libvpx 的安装和配置过程相对简单,用户可以从官方网站下载源代码