精华内容
下载资源
问答
  • 前几天写了一篇...这几天抽了点时间查看了下StringBuilder是如何动态构造字符串的,发现在.NET Core中字符串的构建似乎和我原先猜想的并不完全一样,故此写了这篇文章,如有错误,欢迎指出。StringBuilder...

    前几天写了一篇StringBuilderTextWriter二者之间区别的文章(链接)。当时提了一句没有找到相关源码,于是随后有很多热心人士给出了相关的源码链接(链接),感谢大家。这几天抽了点时间查看了下StringBuilder是如何动态构造字符串的,发现在.NET Core中字符串的构建似乎和我原先猜想的并不完全一样,故此写了这篇文章,如有错误,欢迎指出。

    StringBuilder字段和属性

    字符数组

    明确一点的是,StringBuilder的内部确实使用字符数组来管理字符串信息的,这一点上和我当时的猜测是差不多的。相较于字符串在大多数情况下的不变性而言,字符数组有其优点,即修改字符数组内部的数据不会全部重新创建字符数组(字符串的不变性)。下面是StringBuilder的部分源码,可以看到,内部采用m_ChunkChars字段存储字符数组信息。

    public sealed class StringBuilder
    {
    internal char[] m_ChunkChars;
    ...
    }

    然而,采用字符数组并不是没有缺点,数组最大的缺点就是在在使用前就需要指定它的空间大小,这种固定大小的数组空间不可能有能力处理多次的字符串拼接,总有某次,数组中的空余部分塞不下所要拼接的字符串。如果某次拼接的字符串超过数组的空闲空间时,一种易想到做到的方法就是开辟一个更大的空间,并将原先的数据复制过去。这种方法能够保证数组始终是连续的,然而,它的问题在于,复制是一个非常耗时的操作,如非必要,尽可能地降低复制的频率。在.NET Core中,StringBuilder采用了一个新方法避免了复制操作。

    单链表

    为了能够有效地提高性能,StringBuilder采用链表的形式规避了两个字符数组之间的复制操作。在其源代码中,可以发现每个StringBuilder内部保留对了另一个StringBuilder的引用。

    public sealed class StringBuilder
    {
    internal StringBuilder? m_ChunkPrevious;
    ...
    }

    StringBuilder中,每个对象都维护了一个m_ChunkPrevious引用,按字段命名的意思来说,就是每个类对象都维护指向前一个类对象的引用。这一点和我们常见的单链表结构有点一点不太一样,常见的单链表结构中每个节点维护的是指向下一个节点的引用,这和StringBuilder所使用的模式刚好相反,挺奇怪的。整理下,这部分有两个问题:

    1. 为什么说采用单链表能避免复制操作?

    2. 为什么采用逆向链表,即每个节点保留指向前一个节点的引用?

    对于第一个问题,试想下,如果又有新的字符串需要拼接且其长度超过字符数组空闲的容量时,可以考虑新开辟一个新空间专门存储超额部分的数据。这样,先前部分的数据就不需要进行复制了,但这又有一个新问题,整个数据被存储在两个不相连的部分,怎么关联他们,采用链表的形式将其关联是一个可行的措施。以上就是StringBuilder拼接字符串最为核心的部分了。

    那么,对于第二个问题,采用逆向链表对的好处是什么?这里我给出的原因属于我个人的主观意见,不一定对。从我平时使用上以及一些开源类库中来看,对StringBuilder使用最广泛的功能就是拼接字符串了,即向尾部添加新数据。在这个基础上,如果采用正向链表(每个节点保留下一个节点的引用),那么多次拼接字符串在数组容量不够的情况下,势必需要每次循环找到最后一个节点并添加新节点,时间复杂度为O(n)。而采用逆向链表,因为用户所持有的就是最后一个节点,只需要在当前节点上做些处理就可以添加新节点,时间复杂度为O(1)。因此,StringBuilder内的字符数组可以说是字符串的一个部分,也被称为Chunk。

    举个例子,如果类型为Stringbuilder变量sb内已经保存了HELLO字符串,再添加WORLD时,如果字符数组满了,再添加就会构造一个新StringBuilder节点。注意的是调用类方法不会改变当前变量sb指向的对象,因此,它会移动内部的字符数组引用,并将当前变量的字符数组引用指向WORLD。下图中的左右两图是添加前后的说明图,其中黄色StringBuilder是同一个对象。

    fe4a32f4c103912384215cf02f3d9393.png

    当然,采用链表并非没有代价。因为链表没有随机读取的功能。因此,如果向指定位置添加新数据,这反而比只使用一个字符数组来得慢。但是,如果前面的假设没错的话,也就是最频繁使用的是尾部拼接的话,那么使用链表的形式是被允许的。根据使用场景频率的不同,提供不同的实现逻辑。

    各种各样的长度

    剩下来的部分,就是描述各种各样的长度及其他数据。主要如下:

    public sealed class StringBuilder
    {
    internal int m_ChunkLength;
    internal int m_ChunkOffset;
    internal int m_MaxCapacity;
    internal const int DefaultCapacity = 16;
    internal const int MaxChunkSize = 8000;
    public int Length
    {
    get => m_ChunkOffset + m_ChunkLength;
    }
    ...
    }
    • m_ChunkLength描述当前Chunk存储信息的长度。也就是存储了字符数据的长度,不一定等于字符数组的长度。

    • m_ChunkOffset描述当前Chunk在整体字符串中的起始位置,方便定位。

    • m_MaxCapacity描述构建字符串的最大长度,通常设置为int最大值。

    • DefaultCapacity描述默认设置的空间大小,这里设置的是16。

    • MaxChunkSize描述Chunk的最大长度,也就是Chunk的容量。

    • Length属性描述的是内部保存整体字符串的长度。

    构造函数

    上述讲述的是StringBuilder的各个字段和属性的意义,这里就深入看下具体函数的实现。首先是构造函数,这里仅列举本文所涉及到的几个构造函数。

    public StringBuilder(){
    m_MaxCapacity = int.MaxValue;
    m_ChunkChars = new char[DefaultCapacity];
    }

    public StringBuilder(string? value, int startIndex, int length, int capacity){
    ...
    m_MaxCapacity = int.MaxValue;
    if (capacity == 0)
    {
    capacity = DefaultCapacity;
    }
    capacity = Math.Max(capacity, length);

    m_ChunkChars = GC.AllocateUninitializedArray<char>(capacity);
    m_ChunkLength = length;

    unsafe
    {
    fixed (char* sourcePtr = value)
    {
    ThreadSafeCopy(sourcePtr + startIndex, m_ChunkChars, 0, length);
    }
    }
    }

    private StringBuilder(StringBuilder from){
    m_ChunkLength = from.m_ChunkLength;
    m_ChunkOffset = from.m_ChunkOffset;
    m_ChunkChars = from.m_ChunkChars;
    m_ChunkPrevious = from.m_ChunkPrevious;
    m_MaxCapacity = from.m_MaxCapacity;
    ...
    }

    这里选出了三个和本文关系较为紧密的构造函数,一个个分析。

    1. 首先是默认构造函数,该函数没有任何的输入参数。代码中可以发现,其分配的长度就是16。也就是说不对其做任何指定的话,默认初始长度为16个Char型数据,即32字节。

    2. 第二个构造函数是当构造函数传入为字符串时所调用的,这里我省略了在开始最前面的防御性代码。这里的构造过程也很简单,比较传入字符串的大小和默认容量DefaultCapacity的大小,并开辟二者之间最大值的长度,最后将字符串复制到数组中。可以发现的是,这种情况下,初始字符数组的长度并不总是16,毕竟如果字符串长度超过16,肯定按照更长的来。

    3. 第三个构造函数专门用来构造StringBuilder的节点的,或者说是StringBuilder的复制,即原型模式。它主要用在容量不够构造新的节点,本质上就是将内部数据全部赋值过去。

    从前两个构造函数可以看出,如果第一次待拼接的字符串长度超过16,那么直接将该字符串以构造函数的参数传入比构建默认StringBuilder对象再使用Append方法更加高效,毕竟默认构造函数只开辟了16个char型空间。

    Append方法

    这里主要看StringBuilder Append(char value, int repeatCount)这个方法(位于第710行)。该方法主要是向尾部添加char型字符value,一共添加repeatCount个。

    public StringBuilder Append(char value, int repeatCount){
    ...

    int index = m_ChunkLength;
    while (repeatCount > 0)
    {
    if (index < m_ChunkChars.Length)
    {
    m_ChunkChars[index++] = value;
    --repeatCount;
    }
    else
    {
    m_ChunkLength = index;
    ExpandByABlock(repeatCount);
    Debug.Assert(m_ChunkLength == 0);
    index = 0;
    }
    }

    m_ChunkLength = index;
    AssertInvariants();
    return this;
    }

    这里仅列举出部分代码,起始的防御性代码以及验证代码略过。看下其运行逻辑:

    1. 依次循环当前字符repeatCount次,对每一次执行以下逻辑。(while大循环)

    2. 如果当前字符数组还有空位时,则直接向内部进行添加新数据。(if语句命中部分)

    3. 如果当前字符数组已经被塞满了,首先更新m_ChunkLength值,因为数组被塞满了,因此需要下一个数组来继续放数据,当前的Chunk长度也就是整个字符数组的长度,需要更新。其次,调用了ExpandByABlock(repeatCount)函数,输入参数为更新后的repeatCount数据,其做的就是构建新的节点,并将其挂载到链表上。

    4. 更新m_ChunkLength值,记录当前Chunk的长度,最后将本身返回。

    接下来就是ExpandByABlock方法的实现。

    private void ExpandByABlock(int minBlockCharCount){
    ...
    int newBlockLength = Math.Max(minBlockCharCount, Math.Min(Length, MaxChunkSize));
    ...

    // Allocate the array before updating any state to avoid leaving inconsistent state behind in case of out of memory exception
    char[] chunkChars = GC.AllocateUninitializedArray<char>(newBlockLength);

    // Move all of the data from this chunk to a new one, via a few O(1) pointer adjustments.
    // Then, have this chunk point to the new one as its predecessor.
    m_ChunkPrevious = new StringBuilder(this);
    m_ChunkOffset += m_ChunkLength;
    m_ChunkLength = 0;

    m_ChunkChars = chunkChars;

    AssertInvariants();
    }

    和上面一样,仅列举出核心功能代码。

    1. 设置新空间的大小,该大小取决于三个值,从当前字符串长度和Chunk最大容量取较小值,然后从较小值和输入参数长度中取最大值作为新Chunk的大小。值得注意的是,这里当前字符串长度通常是Chunk已经被塞满的情况下,可以理解成所有Chunk的长度之和。

    2. 开辟新空间。

    3. 通过上述最后一个构造函数,构造向前的节点。当前节点仍然为最后一个节点,更新其他值,即偏移量应该是原先偏移量加上一个Chunk的长度。清空当前Chunk的长度以及将新开辟空间给Chunk引用。

    对于Append(string? value)这个函数的实现功能和上述说明是差不多的,基本都是新数据先往当前的字符数组内塞,如果塞满了就添加新节点并刷新当前字符数组数据再塞。详细的功能可以从L802开始看。这里不做过多说明。

    验证

    当然,以上只是阅读代码的流程,具体是否正确还可以做点测试来验证。这里我做了一个小测试demo。

    var sb = new StringBuilder();
    sb.Append('1', 10);
    sb.Append('2', 6);
    sb.Append('3', 24);
    sb.Append('4', 15);
    sb.Append("hello world");
    sb.Append("nice to meet you");
    Console.WriteLine($"结果:{sb.ToString()}");

    var p = sb;
    char[] data;
    Type type = sb.GetType();
    int count = 0;
    while (p != null)
    {
    count++;
    data = (char[])type.GetField("m_ChunkChars", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(p);
    Console.WriteLine($"倒数第{count}个StringBuilder内容:{new string(data)}");
    p = (StringBuilder)type.GetField("m_ChunkPrevious", BindingFlags.NonPublic | BindingFlags.Instance).GetValue(p);
    }

    这里主要做的是利用Append方法添加不同的数据并将最终结果输出。考虑到内部的细节并没有对外公开,只能通过反射的操作来获取,通过遍历每一个StringBuilder的节点,反射获取内部的字符数组并将其输出。最终的结果如下。

    00ad14cda8e1f67a2bdb966b008b0cd4.png

    这里分析下具体的过程:

    1. 第一句sb = new StringBuilder()。从之前的构造函数代码内可以得知,无参构造函数会生成一个16长度的字符数组。

    2. 第二句sb.Append('1', 10)。这句话意思是向sb内添加10个1字符,因为添加的长度小于给定的默认值16,因此直接将其添加即可。

    3. 第三句sb.Append('2', 6)。在经过上面添加操作后,当前字符数组还剩6个空间,刚好够塞,因此直接将6个2字符直接塞进去。

    4. 第四句sb.Append('3', 24)。在添加字符3之前,StringBuilder内部的字符数组就已经没有空间了。为此,需要构造新的StringBuilder对象,并将当前对象内的数据传过去。对于当前对象,需要创建新的字符数组,按照之前给出的规则,当前Chunk之和(16)和Chunk长度(8000)取最小值(16),最小值(16)和输入字符串长度(24)取最大值(24)。因此,直接创建24个字符空间并存下来。此时,sb对象有一个前置节点。

    5. 第五句sb.Append('4', 15)。上一句代码只创建了长度为24的字符数组,因此,新数据依然无法再次塞入。此时,依旧需要创建新的StringBuilder节点,按照同样的规则,取当前所有Chunk之和(16+24=40)。因此,新字符数组长度为40,内部存了15个字符数据4sb对象有两个前置节点。

    6. 第六句sb.Append("hello world")。这个字符串长度为11,当前字符数组能完全放下,则直接放下。此时字符数组还空余14个空间。

    7. 第七句sb.Append("nice to meet you")。这个字符串长度为16,可以发现超过了剩余空间,首先先填充14个字符。之后多出的2个,则按照之前的规则再构造新的节点,新节点的长度为所有Chunk之和(16+24+40=80),即有80个存储空间。当前Chunk只存储最后两个字符ousb对象有3个前置节点。符合最终的输出结果。

    总结

    总的来说,采用定长的字符数组来保存不定长的字符串,不可能完全避免所添加的数据超出剩余空间这样的情况,重新开辟新空间并复制原始数据过于耗时。StringBuilder采用链表的形式取消了数据的复制操作,提高了字符串连接的效率。对于StringBuilder来说,大部分的操作都在尾部添加,采用逆向链表是一个不错的形式。当然StringBuilder这个类本身有很多复杂的实现,本篇只是介绍了Append方法是如何进行字符串拼接的。

    展开全文
  • 羞,Java 字符串拼接竟然有这么多姿势 如何看一段JAVA代码耗了多少内存 - 最课程(zuikc.com)..._CSDN博客 前段时间上课的时候记得威哥讲到了关于StringBuilder的优势 (尽力还原,并非原话) 如下代码 String a...

    参考资料

    Java 字符串拼接竟然有这么多姿势

    如何看一段JAVA代码耗多少内存 - 最课程(zuikc.com)..._CSDN博客

     

    前段时间上课的时候记得威哥讲到了关于StringBuilder的优势

    (尽力还原,并非原话)

    如下代码

    String a="a";
    String b="b";
    String c="c";
    ​
    System.out.println(a+b+c);

    威哥对代码实际画图大概是这样的

     

    (注意这是错误结论!)

     

     

    用代码来解释就是

    "a"+"b"+"c"; 的实质是

    new StringBuilder(new StringBuilder("a").append("b").toString()).append("c").toString();

     

    使用 "+" 拼接字符串 每一步都会在常量池创建一个新的字符串用来和后面的字符串拼接

    虽然说String的拼接的确有时候效率很低,但是不至于内部代码睿智到这种程度

    这句话在某些情况某些角度来讲的确是对的!

    ==========================以上是错误结论================================

     

    以下是实践内容

     

    所以威哥推荐我们在拼接字符串的时候不要使用

    "a"+"b"+"c"这种形式

    而使用new StringBuilder().append("a").append("b").append("c").toString();

    然而这两种代码真的有区别嘛?

    我写出以下代码测试

    String a="a";
    String b="b";
    String c="c";
    System.out.println(a+b+c);
    System.out.println(new StringBuilder().append(a).append(b).append(c).toString());

    导出编译成jar包后放入JAD反编译查看源码( IDEA我真的是不会用,导出搞了半天 )

    然后得到了如下睿智的代码

    String a = "a";
    String b = "b";
    String c = "c";
    System.out.println(a + b + c);
    System.out.println(a + b + c);

    于是乎,放弃JAD改用java编译器自带的反编译

      javap -c                       对代码进行反汇编

    得到了这段代码

    Code: 0: aload_0 1: invokespecial #1 // Method java/lang/Object."<init>":()V 4: return

    public static void main(java.lang.String[]); Code: 0: ldc #2 // String a 2: astore_1 3: ldc #3 // String b 5: astore_2 6: ldc #4 // String c 8: astore_3 9: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 12: new #6 // class java/lang/StringBuilder 15: dup 16: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V 19: aload_1 20: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 23: aload_2 24: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: aload_3 28: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 31: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 34: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 37: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream; 40: new #6 // class java/lang/StringBuilder 43: dup 44: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V 47: aload_1 48: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 51: aload_2 52: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 55: aload_3 56: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 59: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String; 62: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V 65: return }

    左边是一大段的汇编代码看不懂,整理一下主要代码如下

    // String a
    // String b
    // String c
    ​
    // Field java/lang/System.out:Ljava/io/PrintStream;
    // class java/lang/StringBuilder
    // Method java/lang/StringBuilder."<init>":()V
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    // Method java/io/PrintStream.println:(Ljava/lang/String;)V
    ​
    // Field java/lang/System.out:Ljava/io/PrintStream;
    // class java/lang/StringBuilder
    // Method java/lang/StringBuilder."<init>":()V
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
    // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
    // Method java/io/PrintStream.println:(Ljava/lang/String;)V

    是的,上下两段代码是完全一样的

    生成一个StringBuilder对象,调用空参构造方法,然后执行三次append之后然后toString()

    所以得出结论

    "a"+"b"+"c"的代码最终被翻译成了new StringBuilder().append("a").append("b").append("c").toString();

    根本不存在中间创建一个新的StringBuilder拼接字符串一说

     

    那么StringBuilder相对于String之间的"+"拼接根本优势在于哪里?

    这里参考了一篇CSDN关于字符串拼接讲的非常详解的文章

     

    通俗的说一下大拿的讲解

    String的"+"操作符比较适用于在一句话中进行的字符串拼接操作

    而不适合在一个循环体结构中不断的拼接字符串,因为每一次for循环都会创建一个新的StringBuilder而

    使用StringBuilder可以在循环体外面生成一个StirngBuilder然后每次只需要对相同的StringBuilder对象进行append操作

    为什么阿里巴巴不建议在for循环中使用”+”进行字符串拼接

    实际操作一下有了如下代码

    Runtime runtime=Runtime.getRuntime();
            runtime.gc();;
            String a="";
            long startMemory=0;
            for(int i=0;i<9999;i++)
            {
                a+="a";
            }
            long endMemory=runtime.freeMemory();
            System.out.println("a: "+(endMemory-startMemory));
    ​
            String b="";
            StringBuilder builder=new StringBuilder();
            runtime.gc();
            startMemory=runtime.freeMemory();
            for(int i=0;i<9999;i++)
            {
                builder.append("b");
            }
            endMemory=runtime.freeMemory();
            System.out.println("b: "+(endMemory-startMemory));

    实时查看一下JVM的freeMemory

    注意两次计算间要用gc清理一下内存 (实际计算结果可能与操作系统环境有小偏差)

    调用结果如下

    a: 14177064
    b: -183360

    这里笔者也不太明白为什么第二个计算结果会是一个负数

    不过结果显而易见 第一种"+"的拼接操作消耗了大量内存用于创建StringBuilder对象,用完就扔,无引用指向,留着浪费内存

    综上所述

    平时尽量能用StringBuilder(StringBuffer)就用,String的"+"可能更像是ENUM一样java给提供的语法糖.

    by rzYork

    如果有误 欢迎指错

    展开全文
  • vue拼接字符串

    千次阅读 2019-08-29 10:21:28
    vue拼接字符串 发布时间:2019-05-15 16:15:21 直接上代码: <div class="swiper-slide" v-for="img in imgs">  <img :src="['xxx(需要拼接的字符串)'+img]" alt="" width="100%" height="auto" /> <...

    vue拼接字符串

    发布时间:2019-05-15 16:15:21

    直接上代码:

    <div class="swiper-slide" v-for="img in imgs">
      <img :src="['xxx(需要拼接的字符串)'+img]" alt="" width="100%" height="auto" />
    </div>
    
    展开全文
  • Array拼接字符串

    2017-07-14 00:56:00
    原文发布时间为:2011-01-12 —— 来源于本人的百度文章 [由搬家工具导入]Array拼接字符串本来就是一种投机取巧的无聊玩意,来源是IE6对字符串的+实现错误一般情况下,如果是语义性的字符串,不应该使用Array,比如'...

    原文发布时间为:2011-01-12 —— 来源于本人的百度文章 [由搬家工具导入]

    Array拼接字符串本来就是一种投机取巧的无聊玩意,来源是IE6对字符串的+实现错误
    一般情况下,如果是语义性的字符串,不应该使用Array,比如
    'Hello, my name is ' + name;
    如果字符串是“相似情况的重复”的话,建议使用Array,比如
    var array = [];
    for (i = 0; i < length; i++) {
    array[i] = '<li>' + list[i] + '</li'>;
    }
    document.getElementById('somewhere').innerHTML = array.join('\n');

    转载于:https://www.cnblogs.com/handboy/p/7163938.html

    展开全文
  • 本文首发于公众号:javaadu典型答案由于字符串对象是不可变的,所以每次循环都会对操作符左右两边的字符串进行拷贝,并生成一个新的字符串对象。如果循环n次,则这个过程需要n的平方级的时间;并且在这个过程中还...
  • 假设有一个字符串,我们将对这个字符串做大量循环拼接操作,使用”+”的话将得到最低的性能。但是究竟这个性能有多差?如果我们同时也把StringBuffer,StringBuilder或String.concat()放入性能测试中,结果又会如何呢...
  • 简单描述:拼接html 拼接字符串,说实话,拼接这种东西我自己弄,得花费很多时间,主要是转义字符,单引号,双引号这种小细节调整起来比较麻烦,一旦疏忽多了少了一个符号,页面就有点抽象了,我呢比较粗枝大叶(キ`...
  • ##触发器 触发时间 before after 触发事件 insert update delete 等create table score_log select * from score where 1=0;select * from score_log;##创建触发器dilimiter // ##定义终结符create trigger trg_...
  • 使用String类型拼接字符串时间和空间上都非常狼费 1.创建一个StringBuilder的存储空间,大小为第一个字符串的长度+16 2.将第一个字符串添加到缓冲区中 3.将第二个字符串添加到缓冲区中 4.将缓冲区对象转换为字符串...
  • Java中三种方法拼接字符串时间比较

    千次阅读 2018-04-18 09:57:20
    package opt_string;/** * 比较三种方法拼接时间 * @author Administrator * */public class MyString { public static void main(String[] args) { ... } /** * 比较三种拼接字符串时间 */ sta...
  • sql server中拼接字符串时,需要把datetime型转化为char型才能进行拼接。与int转char类型不同,其需要多加引号: 例子: declare @Dtime datetime set @Dtime = '2020-03-05 14:16:36' select 'INSERT into table1...
  • python拼接字符串方法

    2019-03-30 15:05:38
    +号拼接 例如,print(username + ‘,欢迎光临,’+‘时间是:’+ time) 占位符 %s为string类型,%d为int类型,%.2f为float类型...字符串格式化 例如,print(’{},欢迎光临,时间是:{}’.format(username, time)) ...
  • 在学习Python(3x)的过程中,在拼接字符串的时候遇到了些问题,所以抽点时间整理一下Python 拼接字符串的几种方式。 方式1,使用加号(+)连接,使用加号连接各个变量或者元素必须是字符串类型(<class 'str'>...
  • 拼接字符串的简单类

    2020-01-02 14:48:10
    现在google guava库出了一个joiner类去进行字符串拼接,大大的节省了拼接时间。 我这里简单的写了一个方法去拼接: public static String getStringWithSymbol(String symbol, String... txt) { List<...
  • PHP数组拼接字符串发布时间:2016-01-07 21:44:55作者:佚名阅读:(196)PHP数组转换成字符串使用php开发时,需要将一个数组先降序排列然后再拼接成一个字符串,经过一番查找资料还是没有找到自己想要的方法,不得...
  • time.h(ctime)是c time library,定义了获取和操作日期和时间的函数。 1. 结构 view plain coptypedef long time_t; time_t是长整型,表示的是距(1970年,1月1日08:00:00)的秒数,常常通过time函数...
  • perl拼接字符串的性能优化

    千次阅读 2013-12-01 17:27:07
    在perl中大量的数据 字符串拼接时发现拼接的速度很慢 5000条记录的拼接时间 达到了 300多秒 甚至1000多秒  用的拼接方式如下: $data_str=$data_str.@col_data[$nnn]."']]"; 改为下面这种方式之后性能有了...
  • 字符串拼接

    2021-02-18 14:27:37
    对于需要精确处理,在拼接字符串时要在开始位置插入*,同时在结束位置插入*。 对于需要普通处理的,在拼接字符串时要在开始位置插入#,同时在结束位置插入#。 若是需要精确处理和需要普通处理的开始位置相同,则在...
  • Java的字符串拼接问题...在条件值已知有限的情况下,可不可以通过空间换时间的方式,用HashMap缓存条件对应字符串的关系,去优化频繁字符串拼接与转换的执行效率?测试如下:测试1:字符串拼接public classTestSt...
  • 之前在阅读《阿里巴巴Java开发手册》时,发现有一条是关于循环体中字符串拼接的建议,具体内容如下:那么我们首先来用例子来看看在循环体中用 + 或者用 StringBuilder 进行字符串拼接的效率如何吧(JDK版本为 jdk...
  • onclick事件动态传递参数的话,则需拼接参数,如果书写错误则会报错误,在控制台可以看到错误 2、解决办法 正确的书写形式 3、还有一种传递参数的形式如下 传递方式可适应后端的get、...
  • select CONVERT (CONCAT(YEAR('2018-12-14 16:15:30'), '年第',QUARTER('2018-12-14 16:15:30') ,'季度') USING utf8)  AS preOrderDateType;   ...CONCAT MySQL中拼接字符串的方法 SELECT...
  • java最高精度的时间差System.nanoTime()测试String,StringBuffer,StringBuilder拼接字符串的效率问题 在测试String,StringBuffer,StringBuilder之间的效率时,如果用System.currentTimeMillis()的前后时间差来比较...
  • 为什么Java8中不再需要StringBuilder拼接字符串 来源:codeceo 发布时间:2016-12-27 阅读次数:427 0  在Java开发者中,字符串的拼接占用资源高往往是热议的话题.  让我们深入讨论一下为...
  • Java中对于+和append拼接字符串效率的误解

    万次阅读 多人点赞 2017-11-22 21:04:42
    引言 对于初学Java的人来说,在学习String的时候,肯定有无数个人和我们讲过,”尽量不要使用+拼接字符串,效率不好,应该使用append,你自己循环拼接个十万次自己瞧瞧就知道了“,然后像下面那样给我们演示了一下...
  • (给DotNet加星标,提升.Net技能)转自:iskcalcnblogs.com/iskcal/p/implementation前言写了一篇《.NET中的StringBuilder和...这几天抽了点时间查看了下StringBuilder是如何动态构造字符串的,发现在.NET Core...
  • (给DotNet加星标,提升.Net技能)转自:iskcalcnblogs.com/iskcal/p/implementation前言写了一篇《.NET中的StringBuilder和...这几天抽了点时间查看了下StringBuilder是如何动态构造字符串的,发现在.NET Core...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,503
精华内容 601
关键字:

时间拼接字符串