第五篇 Java常用类(一)字符串相关类

第五篇 Java常用类(一) 字符串相关类

一、String类

(注意:在Java中我们可以这样声明一个字符串String str = 'hello';但是,String并不是像int、char、double等的基本数据类型,它是Java中提供的类,可以使用字面量的方式声明,也可以使用实例化对象的方式:String str = new String('hello');)

1.String的特性

  • 不可变性:String对象是不可变的,查看JDK文档就会发现,String类中每一个看起来会修改String值的方法,实际上都是创建了一个全新的String对象,以包含修改后的字符串内容。而最初的String对象则丝毫未动。《Java编程思想(第4版)》

在这里插入图片描述

  • 不可变对象的体现:对字符串重新赋值或字符串连接(包括调用repalce( )方法),需重写指定内存区域赋值,不能通过原有的value进行修改;

2.String的存储

(1)String实例化方式的对比

在这里插入图片描述

  • 我们声明的字符串常量会存储在字符串常量池中,非常量(对象)存储在堆中。
  • 通过字面量的声明并赋值字符串的方式(不同于new):直接指向存储在字符串常量池中对应的字符串地址。
  • 通过new的方式:String对象指向堆中的地址,该地址存储字符串常量池中对应字符串的地址。
  • 字符串常量池中不会存储相同内容的字符串(如:str1和str2均指向同一个字符串)
(2)String拼接方式的对比

在这里插入图片描述

  • 结论1:常量与常量的拼接结果存储在字符串常量池中,且常量池中不会存在相同内容的常量。
  • 结论2:变量和其他(变量/常量)拼接结果存储在在堆中。
  • 结论3:如果拼接的字符串调用intern()方法,返回得到的字符串也存储在常量池中。
    (和变量拼接就放在堆中,其他在字符串常量池中)

3.String的常用方法

方法作用
int length( )返回字符串长度(value[ ]数组的长度value.length)
char charAt( int index )返回索引值处的字符(即value[index])
boolean isEmpty( )判断是否为空字符串
String toLowerCase( )使用默认语言环境,将String中所有字符转换为小写字符
String toUpperCase( )使用默认语言环境,将String中所有字符转换为大写字符
boolean equals( Object obj )比较字符串内容是否一致
boolean equalsIgnoreCase( String str )比较字符串内容是否一致(忽略大小写)
String trim( )返回忽略前后空白的字符串
String concat( String str )将指定字符串连接到此字符串结尾(相当于+)
int compareTo( String str )比较两个字符串的大小,返回长度差值
String substring( int beginIndex )返回从指定索引开始截取到最后的子字符串
String substring( int beginIndex,int endIndex )返回从指定索引开始截取到指定索引结束(不包括)的子字符串
boolean endsWith( String suffix )判断字符串是否以指定后缀(字符串)结束
boolean startsWith( String prefix )判断字符串是否以指定前缀(字符串)结束
boolean startsWith( String prefix,int toffset )判断字符串从指定索引开始的子字符串是否以指定前缀开始
boolean contains( CharSequence s )判断字符串是否包含指定的char值序列
int indexOf( String str )返回字符串在指定字符串中第一次出现的索引
int indexOf( String str,int fromIndex )返回字符串在指定字符串的指定索引第一次出现的索引
int lastIndexOf( String str )返回字符串在指定字符串中从右开始出现的索引
int lastIndexOf( String str,int fromIndex )返回字符串在指定字符串从右开始到指定索引开始出现的索引
String replace( char oldChar,char newChar )返回通过newChar替换原来的oldChar得到的字符串
String replace( CharSequence target,CharSequence replacement )使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String replaceAll( String regex,String replace )根据指定的字符串替换匹配的正则表达式的所有字符串
String replaceFirst( String regex,String replace )根据指定的字符串替换匹配的正则表达式的第一个子字符串
boolean matches( String regex )判断字符串是否匹配指定的正则表达式
String[ ] split( String regex )根据指定的正则表达式拆分字符串
String[ ] split( String regex,int limit )根据指定正则表达式拆分字符串,超出limit放置最后一个元素

4.String的转换

(1)字符串转基本数据类型、包装类
方法作用
Integer.parseInt( String str )字符串转整型
Integer.parseByte( String str )字符串转字节型
Integer.parseFloat( String str )字符串转浮点型
…………
(2)基本数据类型转字符串
方法作用
valueOf( int n )int型转字符串
valueOf( byte b )字节型转字符串
valueOf( float f )浮点型转字符串
…………
(3)字符数组char[ ]转字符串
String的构造器作用
String( char [ ] )将字符数组转成字符串
String( char [ ],int offset,int length )将指定位置开始和长度的字符数组转成字符串
(4)字符串转字符数组char[ ]
方法作用
toCharArray( )字符串转字符数组
getChars( int srcBegin,int srcEnd,char[] dst,int dstBegin )指定字符串转字符数组
(5)字节数组byte[ ]转字符串
String的构造器作用
String( byte[ ] )使用默认字符集转换byte数组为字符串
String( byte[ ],int offset,int length )使用默认字符集转换byte数组的指定索引、长度为字符串
(6)字符串转字节数组
方法作用
getBytes( )使用默认字符集转换将字符串为字符数组
getBytes( String charsetName )使用指定字符集转换将字符串为字符数组

二、StringBuffer类和StringBuilder类

上面所讲的String类是一个不可变的对象(不可变序列的字符串),接下来的StringBuffer和StringBuilder类均是可变的

1.String、StringBuffer和StringBuilder的区别

String:不可变的字符序列
StringBuffer:可变的字符序列,线程安全(方法均为synchronized声明的同步方法),但效率较低
StringBuilder:可变的字符序列,线程不安全,效率高(JDK 5.0新增)
(String、StringBuffer和StringBuilder底层都是使用byte[ ]数组来存储,而StringBuffer和StringBuilder是可变的,所以底层数组没有用final声明,而String类是不可变的,所以底层存储的数组用final声明private final byte[ ] value。PS:老版本JDK是char型数组)

2.StringBuffer和StringBuilder的底层实现

在使用String类时,我们操作字符串(对字符串重新赋值或字符串连接,包括调用repalce( )方法),不能通过底层原有的byte[] value数组进行修改,而是需要在内存中重新创建一个String对象,所以才说String类是一个不可变的对象;StringBuffer类和StringBuilder类与其不同,都是可变的对象,那么这两个类的底层是如何实现其的"可变"的呢?

(1)数组byte[ ] value的容量

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

(2)代码验证(一)

【验证1-1】创建一个初始化为空字符的(空参)的StringBuffer对象,底层的byte[ ] value默认容量大小为16。
【验证1-2】创建一个初始化为字符串str(带参)的StringBuffer对象,底层的byte[ ] value默认容量大小为str.length( )+16

import org.testng.annotations.Test;

public class StringTest {
    @Test
    public void test3(){
        StringBuffer strBuffer1 = new StringBuffer("");
        /**
         *【验证1-1】创建一个初始化为空字符的(空参)的StringBuffer对象,
         * 底层数组默认容量大小为16
        **/
        System.out.println("初始化为空字符串的长度:"+strBuffer1.length());//""长度0
        System.out.println("初始化为空字符串byte[] value的容量大小:"+strBuffer1.capacity());//16

        /**
         *【验证1-2】创建一个初始化为str字符串(带参)的StringBuffer对象,
         * 底层数组默认容量大小为str.length()+16 
        **/
        StringBuffer strBuffer2 = new StringBuffer("hello");
        System.out.println("初始化为指定字符串的长度:"+strBuffer2.length());//"hello"长度5
        System.out.println("初始化为指定字符串时byte[] value的容量大小:"+strBuffer2.capacity());//21
    }
}

在这里插入图片描述

到了这里,如果调用strBuffer2.append('aaaaa')直到超出原初始化的长度21,数组即将越界,底层是如何实现其容量的扩容呢?

(3)数组byte[ ] value的扩容

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

(4)代码验证(二)

【验证2-1】默认情况下,StringBuffer底层value数组扩容后的容量为原来的2倍+2。
【验证2-2】当需要的容量超过原数组容量的2倍+2,则直接扩容为所需容量。

import org.testng.annotations.Test;

public class StringTest {
    @Test
    public void test3(){
        /**
         * 【验证2-1】默认情况下,StringBuffer底层value数组扩容后的容量为原来的2倍+2。
         * */
        StringBuffer stringBuffer = new StringBuffer();
        System.out.println("当前字符串长度:"+stringBuffer.length());//0
        System.out.println("当前value数组容量:"+stringBuffer.capacity());//16

        stringBuffer.append("HelloWorldHelloWorld");   //length = 20
        System.out.println("扩容字符串长度:"+stringBuffer.length());//20
        System.out.println("扩容后value数组容量:"+stringBuffer.capacity());//34
    }
    @Test
    public void test4(){
        /**
         * 【验证2-2】当需要的容量超过原数组容量的2倍+2,则直接扩容为所需容量。
         * */
        StringBuffer stringBuffer = new StringBuffer();
        System.out.println("当前字符串长度:"+stringBuffer.length());//0
        System.out.println("当前value数组容量:"+stringBuffer.capacity());//16

        stringBuffer.append("HelloWorldHelloWorldHelloWorldHelloWorld");   //length = 40
        System.out.println("扩容字符串长度:"+stringBuffer.length());//40
        System.out.println("扩容后value数组容量:"+stringBuffer.capacity());//40
    }
}

在这里插入图片描述

3.StringBuffer和StringBuilder的常用方法

方法作用
StringBuffer append(xxx)字符串拼接(增)
StringBuffer insert(int offset,xxx)在指定位置插入元素(增)
StringBuffer delete(int start,int end)删除字符串元素(删)
StringBuffer replace(int start,int end,String str)修改指定位置的元素(改)
setCharAt(int n,char ch)修改指定位置的元素(改)
char charAt(int n)返回指定位置的元素(查)
StringBuffer reverse( )字符串逆序排列
……(其他与String类似)……
  • 遍历数组元素

    for(int i=0;i<stringBuffer.length();i++){
        System.out.print(stringBuffer.charAt(i));
    }
    

4.String、StringBuffer和StringBuilder效率

  • StringBuilder > StringBuffer > String
import org.testng.annotations.Test;

public class StringTest {
    @Test
    public void test6() {
        //初始设置
        long startTime = 0L;
        long endTime = 0L;
        String text = "";
        StringBuffer buffer = new StringBuffer("");
        StringBuilder builder = new StringBuilder("");
        //开始对比
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            buffer.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuffer的执行时间: " + (endTime - startTime));
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            builder.append(String.valueOf(i));
        }
        endTime = System.currentTimeMillis();
        System.out.println("StringBuilder的执行时间: " + (endTime - startTime));
        startTime = System.currentTimeMillis();
        for (int i = 0; i < 100000; i++) {
            text = text + i;
        }
        endTime = System.currentTimeMillis();
        System.out.println("String的执行时间: " + (endTime - startTime));
    }
}

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AF_INET6

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值