欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

java基础-字符串

程序员文章站 2022-04-16 16:36:43
在开发中,字符串String类型是我们使用很频繁的对象了(注意它不是基本数据类型)。知道如何创建字符串、常用的方法、相关类的使用、字符串常量池等是我们技能中必不可少的一部分。比如它能:减少内存消耗、加快程序运行速度、提高我们的开发效率等...

前言

  在开发中,字符串String类型是我们使用很频繁的对象了(注意它不是基本数据类型)。知道如何创建字符串、常用的方法、相关类的使用、字符串常量池等是我们技能中必不可少的一部分。比如它能:减少内存消耗、加快程序运行速度、提高我们的开发效率等。

  有问题的地方或者遗漏的知识点请大佬及时指正!!

一、String

1.1 从类分析String

java基础-字符串

  • 通过源码,我们可以看到String被final修饰,说明这个类不能被继承;而对应的value也被final修饰,值是不可变的,每次操作都会是新的String对象,然后将指针指向新的String对象。
  • 我们也应该注意:String不属于基本类型。8种基本数据类型:byte、short、int、long、float、double、char、boolean,而String属于对象。

1.2 String 常用方法

java基础-字符串

1.2.1 intern()

public native String intern();
  • 这个方法会将创建的字符串放入字符串常量池。平时开发中,我们在代码中没有将一些字符串定义字符串常量变量,但是又经常使用某些字符串,为了减少频繁创建对象和内存的消耗,我们可以在对应的字符串后边加上这个方法。

1.2.2 join()

方法源码如下:

public static String join(CharSequence delimiter, CharSequence... elements) {
        Objects.requireNonNull(delimiter);
        Objects.requireNonNull(elements);
        // Number of elements not likely worth Arrays.stream overhead.
        StringJoiner joiner = new StringJoiner(delimiter);
        for (CharSequence cs: elements) {
            joiner.add(cs);
        }
        return joiner.toString();
    }
  • delimiter 表示拼接符号,也就是分隔符
  • elements 需要拼接的数据

平时我们需要将多个字符串拼接起来,就可以用这个方法。这里有个StringJoiner对象,后边介绍

    @Test
    public void testString(){
        //将a b c通过 "," 拼接
        System.out.println(String.join(",", new String[]{"a","b","c"}));
    }

1.3 String str="i"和String str=new String(“i”)一样吗?

 不一样,因为内存的分配方式不一样,前者Java虚拟机会将其分配到常量池中,后者会被分配都堆内存中

二、StringJoiner

java基础-字符串
顾名思义,这个类用于字符串连接。prefix表示前缀,delimiter表示分隔符,suffix表示后缀。

2.1 用法

    List<String> stringList = new ArrayList<>(3);
    stringList.add("a");
    stringList.add("b");
    stringList.add("c");
    //表示用用逗号","分隔,"["作为前缀,用"]"作为后缀
    StringJoiner stringJoiner = new StringJoiner(",", "[", "]");
    for(String str:stringList){
        stringJoiner.add(str);
    }
    System.out.println(stringJoiner);
    System.out.println(stringJoiner.merge(stringJoiner));

输出结果:
java基础-字符串

2.2 源码分析

1.进入add方法

  public StringJoiner add(CharSequence newElement) {
        prepareBuilder().append(newElement);
        return this;
    }

2.进入prepareBuilder方法

   private StringBuilder prepareBuilder() {
        if (value != null) {
            value.append(delimiter);
        } else {
            value = new StringBuilder().append(prefix);
        }
        return value;
    }

我们会发现,StringJoiner底层字符串拼接用了StringBuilder,同时在拼接上 了前缀或者分隔符。

3.进入toString()

 @Override
    public String toString() {
        if (value == null) {
            return emptyValue;
        } else {
            if (suffix.equals("")) {
                return value.toString();
            } else {
                int initialLength = value.length();
                String result = value.append(suffix).toString();
                // reset value to pre-append initialLength
                value.setLength(initialLength);
                return result;
            }
        }
    }

重写了toString方法,添加上后缀。

2.3 总结

当出现拼接字符串的用上String.join或者StringJoiner,完美,就不用自己定义一个String 或者StringBuilder慢慢拼接了。

三、StringBuilder和StringBuffer

3.1 StringBuilder

3.1.1 从类分析StringBuilder

java基础-字符串
java基础-字符串

通过类的关系我们可以看出:

  • StringBuilder被final修饰,这个类不能被继承。
  • StringBuilder继承AbstractStringBuilder这个抽象类,底层采用数组,和String的区别就是没有被final修饰,值可变。这里也就是出现大量字符串拼接用其代替String的原因,String 需要不断的生成新的对象,而StringBuilder只需要改变值。
  • 默认的情况下,value的大小是16

3.1.2 StringBuilder如何扩容

  知道对象底层如何扩容,在新建对象的是否对初始化大小,能够较少内存的消耗(可以让这个对象扩容的合理,减少无用的空间),也可以在在一定程度上加快程序的运行速度(底层数组的长度变了,减少了循环的次数)

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;
    }

每次调用append实则调用父类AbstractStringBuilder 的append方法,进入ensureCapacityInternal->expandCapacity

  /**
     * This implements the expansion semantics of ensureCapacity with no
     * size check or synchronization.
     */
    void expandCapacity(int minimumCapacity) {
    	// 将新的大小设置为当前值长度的二倍加上2
       int newCapacity = value.length * 2 + 2;
       //比较newCapacity 和minimumCapacity(=拼接的长度+原来值的长度)的值,将newCapacity 设置中间一个大的
        if (newCapacity - minimumCapacity < 0)
            newCapacity = minimumCapacity;
        if (newCapacity < 0) {
            if (minimumCapacity < 0) // overflow
                throw new OutOfMemoryError();
            newCapacity = Integer.MAX_VALUE;
        }
        //将原来的值,赋值到新的数组,并赋值给value
        value = Arrays.copyOf(value, newCapacity);
    }

Arrays.copyOf方法如下:
java基础-字符串

3.2 StringBuffer

java基础-字符串

在方法上加了锁,是线程安全的。其他的和StringBuilder类似。

本文地址:https://blog.csdn.net/qq_32748869/article/details/109813465

相关标签: Java基础