java基础-字符串(已经迁移到个人博客)

前言

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

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

一、String

1.1 从类分析String

在这里插入图片描述

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

1.2 String 常用方法

在这里插入图片描述

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

在这里插入图片描述
顾名思义,这个类用于字符串连接。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));

输出结果:
在这里插入图片描述

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

在这里插入图片描述
Q4ODY5,size_16,color_FFFFFF,t_70#pic_center)##

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

  • 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方法如下:
在这里插入图片描述

3.2 StringBuffer

!](https://img-blog.csdnimg.cn/20201125192939306.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FxXzMyNzQ4ODY5,size_16,color_FFFFFF,t_70#pic_center)

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值