带你走进Java字符串的小世界
创始人
2024-05-01 02:18:43
0

目录

一. String

1. 什么是String

2. String常用构造器

3. 字符串的判断

4. 字符串的获取

5. 字符串的转换

6. 字符串比较和替换

7. 字符串的切割

二. StringBuffer与StringBuilder

2.1 关于StringBuffer

2.1.1 定义

2.1.2 构造方法

2.2 关于StringBuffer

三. StringJoiner的使用

四. 关于常量池的面试


🐼个人主页:爪哇斗罗

🐼博主介绍:一名打工人

🐼签名:圣人之道,为而不争。

🐼一起交流,一起进步,一起互动。

在这里插入图片描述

一. String

1. 什么是String

首先,String属于引用数据类型,而不是基本数据类型。它是用来存储字符串的,使用双引号括起来的Unicode字符序列。

每个用双引号""括起来的都是属于String的一个实例。

String str = "hello"

阅读源码(Java8)会发现,String实现Serializable接口,表示字符串可以被序列化。

同时还实现Comparable接口表示字符串可以比较大小。

public final class Stringimplements java.io.Serializable, Comparable, CharSequence {private final char value[];// ①
}

标注①可看出Java使用char[]来存储字符串的值,Java9以后使用byte[]存储字符串。由此说明Sting底层实际上是一个字符数组

所以上述的"hello"实际上存的是['h','e','l','l','o']。

除此之外,计算机并不会存储像h,e甚至是中文这样的字符,此时就和编码表也就是字符集有关系。

指定不同的字符集,程序底层会将对应的字符按照对应的编码表进行编码存储至内存或者磁盘中。

常见的字符集编码有utf8,GBK等。utf8一个字符对应三个字节,GBK一个字符对应两个字节

2. String常用构造器

String()构造一个空的字符串
String(byte[] arr)将字节数组转换为字符串
String(byte[] arr, int offset, int lengh)将字节数组部分转换为字符串
String(char[] arr)将char字节数组转换为字符串
String(char[] arr, int offset, int length)将char字节数组部分转换为字符串
String(String original)字符串常量构建字符串
String(byte bytes[], int offset, int length, Charset charset)将字节数组部分转换为指定字符集的字符串
byte[] b = {97,98,99,100};	
String str = new String(b);
System.out.println(str);//abcd

byte数组转换为String字符串会有一个解码的过程,就是将b存入内存中然后进行解码输出对应字符串得到abcd。

public String(byte bytes[], int offset, int length) {checkBounds(bytes, offset, length);// 解码this.value = StringCoding.decode(bytes, offset, length);
}

char数组转String字符串方式都和上述大同小异,这里不在赘述。

3. 字符串的判断

boolean equals(Object obj)判断两个字符串内容是否相等
boolean equalsIgnorecase(String str)忽略大小写判断两个对象是否相等
boolean contains(String str)判断大字符串是否包含小字符串
​​​​​​boolean ​startsWith(String str)判断是否以指定的字符串开头
boolean endsWIth(String str)判断是否以指定的字符串结尾
boolean isEmpty()判断字符串是否为空
public static void main(String[] args) {String s1 = "abcde";String s2 = "AbCde";String s3 = "abcde";//equals(): 比较两个字符串是否相等。System.out.println(s1.equals(s2));//trueSystem.out.println(s1.equals(s3));//false//equalsIgnoreCase():忽略大小写比较字符串相等。System.out.println(s1.equalsIgnoreCase(s2));//trueSystem.out.println(s1.equalsIgnoreCase(s3));//true//contains():是否包含指定字符串。System.out.println(s1.contains("bd"));//false//startsWith():是否以指定字符串开头System.out.println(s1.startsWith("ab"));//true// 第二个参数表示在索引为2的字符开始比较System.out.println(s1.startsWith("cde",2));//true//是否以字符串结尾System.out.println(s1.endsWith(s3));//true//是否为空System.out.println(s1.isEmpty());//false
}

4. 字符串的获取

length()获取字符串的长度
charAt(inx index)获取某个索引的字符
indexOf(int ch)获取指定字符在字符串第一次出现的位置,可以写对应的ASCALL码值
indexOf(int ch, int fromIndex)获取从指定的索引开始,字符出现的位置
indexOf(String str)获取指定的字符串在原字符串的位置
indexOf(String str, int fromIndex)获取从指定的索引开始,字符串第一次出现的位置
lastIndexOf(int ch)获取指定字符最后一次出现的索引值
lastIndexOf(String str,int fromIndex)获取指定字符串最后出现的索引值
subString(int start)从指定位置开始截取字符串
subString(int start, int end)从指定位置到指定位置截取字符串
public static void main(String[] args) {String str = "abcdeababcdacaeca";//长度System.out.println(str.length());//17//获取某个索引的字符System.out.println(str.charAt(1));//b//获取最后一个元素值System.out.println(str.charAt(str.length() - 1));//a//获取'a'第一次出现的索引值System.out.println(str.indexOf('a'));//0System.out.println(str.indexOf(97));//0//从第二个索引值开始,'a'第一次出现的位置System.out.println(str.indexOf('a', 2));//5//获取"bc"第一次出现的索引值System.out.println(str.indexOf("bc"));//1//从2索引开始"ad"第一次出现的索引值System.out.println(str.indexOf("ad", 2));//-1//获取'a'最后一次存储的索引值System.out.println(str.lastIndexOf('a'));//16//获取'bc'最后一次出现的索引值System.out.println(str.lastIndexOf("bc"));//8//从7索引结束前获取'a'最后一次索引值System.out.println(str.lastIndexOf('a', 7));//7System.out.println(str.lastIndexOf('c', 6));//2//从索引5截取到末尾String s1 = str.substring(5);System.out.println(s1);//ababcdacaeca//"abcdeabca" ===> "deab"String s2 = str.substring(3, 7);System.out.println(s2);
}

注意:如果没有找到都会返回-1

5. 字符串的转换

byte[] getBytes()将字符串转换为字节数组
byte[] getBytes(String charset)通过指定的字符集,将字符串转成字节数组
char[] toCharArray()将字符串转成字符数组
static valueOf(char[] chs)将字符数组转成字符串
static valueOf(Object obj)将任意的引用数据转成字符串
toLowerCase()转成小写
toUpperCase()转成大写
concat(String str)字符串连接
trim()去除两边空格
public static void main(String[] args) {String s = "Ab三上悠亚";//String转为byte[]byte[] bys =s.getBytes();//[65, 98, -28, -72, -119, -28, -72, -118, -26, -126, -96, -28, -70, -102]System.out.println(Arrays.toString(bys));//String转为char[]char[] c = s.toCharArray();//[A, b, 三, 上, 悠, 亚]System.out.println(Arrays.toString(c));//其它大部分类型转StringSystem.out.println(String.valueOf(100));//100System.out.println(String.valueOf(false));//falseSystem.out.println(String.valueOf('a'));//aSystem.out.println(String.valueOf(3.23f));//3.23System.out.println(String.valueOf(c,0,3));//Ab三 从0索引开始截取三个字符char[] data = {'A','B','c'};System.out.println(String.valueOf(data));//ABcSystem.out.println(s.toLowerCase());//ab三上悠亚System.out.println(s.toUpperCase());//AB三上悠亚
}

6. 字符串比较和替换

replace(char old, char new)新的字符替换旧的字符
replace(String old, Stringnew)新的字符串替换旧的字符串
String replace(CharSequence target, CharSequence replacement)替换指定的字符序列
int compareTo(String str)字典比较字符串
int compareToIgnoreCase(String str)忽略大小写比较
public static void main(String[] args) {String s = "abc三上悠亚abc";//b替换B 字符替换String s1 = s.replace('b', 'B');System.out.println(s1);//aBc三上悠亚aBc//三上悠亚替换为JAPAN字符串替换String s2 = s.replace("三上悠亚", "JAPAN");System.out.println(s2);//abcJAPANabc//替换指定的字符序列String s4 = "abc";String s5 = "abcd";String s6 = s.replace(s4, s5);System.out.println(s6);//abcd三上悠亚abcd
}

7. 字符串的切割

String[] split(String regex, int limit)将字符串按照某种方式进行分割并指定分割多少
String[] split(String regex)将字符串按照某种方式进行分割
public static void main(String[] args) {String str = "1-2-3-4-5";// 按照规则来切割字符串String[] split1 = str.split("-");// 按照规则来切割几段字符串String[] split2 = str.split("-",2);// [1,2,3,4.5]System.out.println(Arrays.toString(split1));// [1,2-3-4-5]System.out.println(Arrays.toString(split2));
}

二. StringBuffer与StringBuilder

2.1 关于StringBuffer

2.1.1 定义

作为线程不安全的可变字符序列,StringBuilder类似于String的字符缓冲区,可以看做是一个高级的String。

与String的区别就是,它是一个可变的字符序列。记住:StringBuilder是线程不安全的!!!所以在多线程场景下不可使用。

2.1.2 构造方法

StringBuilder构造

  • StringBuilder():空的构造,底层默认创建容量为16的字符缓冲区对象。
  • StringBuilder(int capacity):可以指定容量创建StringBuilder对象。
  • StringBuilder(String str):创建指定字符串的StringBuilder对象。
    StringBuilder sb = new StringBuilder();System.out.println(sb);//空System.out.println(sb.length());//0System.out.println(sb.capacity());//16StringBuilder sb1 = new StringBuilder(100);System.out.println(sb1);//空System.out.println(sb1.length());//0System.out.println(sb1.capacity());//100StringBuilder sb3 = new StringBuilder("java");System.out.println(sb3);//javaSystem.out.println(sb3.length());//4System.out.println(sb3.capacity());//20

StringBuilder成员方法

  • 增加功能

    • String append(Object obj):括号中可以是任意类型

    • insert(int offset, String str):任意地方添加指定类型

  • 删除功能

    • deleteCharAt(int index) 指定位置删除对应的元素
    • delete(int index, int end)删除[index,end-1]之间的元素
  • 修改功能:

    • setCharAt(int n, char ch):
    • replace(int start,int end,String str):
  • 查询功能

    • charAt(int n):
    • int Capacity():
    • int length():
  • 反转功能

    • reverse() 反转功能
  • 截取功能

    • String substring(int start):截取指定位置一直到末尾
    • String substring(int start,int end):截取[start,end-1]范围
StringBuilder sb = new StringBuilder();
//添加
sb.append('j').append("av").append(false).append(100);//javfalse100
sb.insert(1, false);//jfalseavfalse100
//删除
sb.deleteCharAt(0);//删除第一个字符 falseavfals100
sb.delete(0, 3);//删除[0-2]的字符  seavfals100
//修改
sb.setCharAt(3, 't');//seatfalse100
sb.replace(3,7,"true");//seatruelse100
//查询元素
System.out.println(sb.charAt(6));//e
System.out.println(sb.length());//12
System.out.println(sb.capacity());//初始容量16
//截取功能
System.out.println(sb.substring(3));//truelse100
System.out.println(sb.substring(4, 7));//rue 截取[4,6]        

2.2 关于StringBuffer

StringBuffer与StringBuilder的用法是一模一样的,这里不再赘述相关方法,主要对比他们两有什么区别。

常见的String,StringBuffer,StringBuilder的面试题。

  • 可变性

    • String用final修饰,不可变
    • StringBuffer与StringBuilder都是继承AbstratBuilder类,存储的char[]并未用final修饰,是可变的
  • 线程安全性

    • String对象不可变,可以视为线程安全
    • StringBuffer加了同步锁,线程安全
    • StringBuilder方法未加同步锁,线程不安全
  • 性能

    • 每次对String进行赋值时都会产生新对象,然后将指针指向新的对象。
    • StringBuffer每次都会对对象的本身进行操作,而不是产生新的对象去引用它,相同情况下,使用StringBuilder的性能会提高,但是会有线程不安全的风险。

代码比较StringBuilder与StringBuffer的性能:

    private static void demo02() {StringBuilder sb = new StringBuilder("abc");//当前时间long l1  = System.currentTimeMillis();for(int i=0; i<100000;i++) {sb.append("hello");}//跑完循环long l2  = System.currentTimeMillis();System.out.println("String连接耗时:"+ (l2 -l1));}private static void demo01() {String s = "abc";//当堆空间溢出会发生OutOfMemoryError//当前时间long l1  = System.currentTimeMillis();for(int i=0; i<100000;i++) {s += "hello";}//跑完循环long l2  = System.currentTimeMillis();System.out.println("String连接耗时:"+ (l2 -l1));}

如何使用三者?

  • 操作少量的数据:String
  • 单线程操作大量数据:StringBuilder
  • 多线程操作大量数据:StringBuffer

三. StringJoiner的使用

上面,我们总是使用SpringBuilder去拼接字符串,使用的分割符号很多。

并且代码量相对来说也是比较多的,Java1.8给我们提供了一个StringJoiner类来专门拼接字符串。

先看一个简单的例子,将集合中的元素通过逗号分割开并输出一个字符串:

public static void main(String[] args) {List integers = new ArrayList();integers.add(1);integers.add(2);integers.add(3);integers.add(4);integers.add(5);StringBuilder stringBuilder = new StringBuilder();for (Integer integer : integers) {stringBuilder.append(integer + ",");}// 1,2,3,4,5System.out.println(stringBuilder.toString().substring(0, stringBuilder.length() - 1));}

这样的代码是不是看起来繁杂,并且只能通过手动去拼接,如果使用StringJoiner去拼接字符串就会一步到位:

public static void main(String[] args) {List integers = new ArrayList();integers.add(1);integers.add(2);integers.add(3);integers.add(4);integers.add(5);	// 序号1StringJoiner stringJoiner = new StringJoiner(",");for (Integer integer : integers) {stringJoiner.add(String.valueOf(integer));}// 1,2,3,4,5System.out.println(stringJoiner.toString());}

以上两段代码输出的结果都是一样的,都是1,2,3,4,5,如果我们需要输出这样的字符串[1,2,3,4,5]怎么办?其实StringJoiner也提供了这样的方法,只需要将上述的序号1代码换成:

StringJoiner stringJoiner = new StringJoiner(",","[","]");

添加两个参数,分别代表的是前缀与后缀,是不是非常简单呢,这个在开发中也是很常用的。

如果获取的数据是空的,我们呢又要给其设置一个默认的值。

那么可以使用setEmptyValue()方法就可以了:

stringJoiner.setEmptyValue("1");

拼接字符串使用StringJoiner还是挺方便的,赶快用起来吧!

四. 关于常量池的面试

先看如下所示的代码:s1与s2相等吗?

String s1 = new String(abc");
String s2 = "abc";

s1与s2虽然内容都是一样,但是两者是不相等的。

因为String是引用数据类型,如果比较相等(==),两者比较的是地址与内容是否相等。这就会引出常量池的概念。

s1是引用对象,首先会在栈内存中会开辟一个s1的引用对象的空间,而abc这个字符串常量是存在方法区常量池中。通过s1这个对象引用指向abc。

s2则是s2的一个引用指向了abc。

注意:JDK1.7之前,常量池在方法区中,JDK1.7及以后常量池放在了堆里面,我们通常指的的是1.7之前的常量池

下面来看==与equals()的比较字符串是否相等的使用。

  • == 比较的地址和内容都相等才相等
  • equals()内容相等即是相等

理解上面两句,看如下代码就会清晰很多:

    String s1 = "123";①String s2 = "123";②String s3 = new String("123");③System.out.println(s1==s2);//正确System.out.println(s1==s3);//错误

只要明白了内存分布,判断不成问题。对于①,②来说,s1,s2都在栈内存中。

对于③来说,会先在栈中开辟一个内存空间存放引用对象s3。

然后会在堆内存中重新开辟空间存放new String("123")中的String匿名对象的值123所以s1==s3是错误的!!!

对于equals()就不一样了比较的是内容是否相等,三者内容都是相等的,所以equals是true

PS: null," "的区别

null代表的是空对象,并不是字符串,可以赋给任何对象,字符串中表示只是一个引用,还没有内存空间的分配

“ ”表示引用已经指向了 一块内存空间了,是一个实际的东西,可以进行操作了,表示一个长度为0的字符串

练习一:

String s1 = new String("hello");
String s2 = new String("hello");
System.out.println(s1==s2);
System.out.println(s1.equals(s2));
String s3 = new String("hello");
String s4 = "hello";
System.out.println(s3==s4);
System.out.println(s3.equals(s4));
String s5 = "hello";
String s6 = "hello";
System.out.println(s5==s6);
System.out.println(s5.equals(s6));

答案:F T F T T T

关于字符串的拼接

  • 常量与常量的拼接还在常量池中
  • 常量池不可有相同的常量
  • 拼接的时候,只要存在变量都会存到堆中
  • 调用intern()方法返回常量池里面的常量
    String s1 = "hello";String s2 = "world";String s3 = "helloworld";System.out.println(s3==(s1+s2));//F 变量的连接存在堆中不相等System.out.println(s3==(s1+s2).intern());//T 获取的是值相等System.out.println(s3.equals(s1+s2));//T 获取内容相等System.out.println(s3=="hello" + "world");//T 常量与常量连接还在常量池中System.out.println(s3.equals("hello"+"world"));//T	内容相等	

相关内容

热门资讯

安卓双系统添加应用,轻松实现多... 你有没有想过,你的安卓手机里可以同时运行两个系统呢?听起来是不是很酷?想象一边是熟悉的安卓系统,一边...
pipo安卓进系统慢,探究pi... 最近是不是发现你的Pipo安卓系统更新或者运行起来特别慢?别急,今天就来给你好好分析分析这个问题,让...
怎样使用安卓手机系统,安卓手机... 你有没有发现,安卓手机已经成为我们生活中不可或缺的一部分呢?从早晨闹钟响起,到晚上睡前刷剧,安卓手机...
双系统安卓安装caj,轻松实现... 你有没有想过,你的安卓手机里装上双系统,是不是就能同时享受安卓和Windows系统的乐趣呢?没错,这...
安卓使用ios系统教程,安卓用... 你是不是也和我一样,对安卓手机上的iOS系统充满了好奇?想要体验一下苹果的优雅和流畅?别急,今天我就...
安卓系统gps快速定位,畅享便... 你有没有遇到过这样的情况:手机里装了各种地图导航软件,但每次出门前都要等上好几分钟才能定位成功,急得...
安卓手机系统更新原理,原理与流... 你有没有发现,你的安卓手机最近是不是总在提醒你更新系统呢?别急,别急,让我来给你揭秘一下安卓手机系统...
安卓系统通知管理,全面解析与优... 你有没有发现,手机里的通知就像是一群调皮的小精灵,时不时地跳出来和你互动?没错,说的就是安卓系统的通...
安卓系统手机哪买,揭秘哪里购买... 你有没有想过,拥有一部安卓系统手机是多么酷的事情呢?想象你可以自由安装各种应用,不受限制地探索各种功...
安卓系统 ipv4,基于安卓系... 你知道吗?在智能手机的世界里,有一个系统可是无人不知、无人不晓,那就是安卓系统。而在这个庞大的安卓家...
目前安卓是什么系统,探索安卓系... 亲爱的读者,你是否曾好奇过,如今安卓系统究竟是什么模样?在这个科技飞速发展的时代,操作系统如同人体的...
安卓6.0系统比5.0,从5.... 你有没有发现,自从手机更新了安卓6.0系统,感觉整个人都清爽了不少呢?没错,今天咱们就来聊聊这个话题...
安卓2.36系统升级,功能革新... 你知道吗?最近安卓系统又来了一次大变身,那就是安卓2.36系统升级!这可不是一个小打小闹的更新,而是...
安卓系统源码怎么打开,并可能需... 你有没有想过,安卓系统的源码就像是一扇神秘的门,隐藏着无数的技术秘密?想要打开这扇门,你得掌握一些小...
安卓8.0系统体验视频,智能革... 你有没有听说安卓8.0系统最近可是火得一塌糊涂啊!作为一个紧跟科技潮流的数码达人,我当然要来给你好好...
宣传系统漫画app安卓,探索安... 亲爱的读者们,你是否曾在某个午后,百无聊赖地打开手机,想要寻找一些轻松愉悦的读物?今天,我要给你介绍...
鸿蒙替换安卓系统吗,开启智能生... 你知道吗?最近科技圈里可是炸开了锅,因为华为的新操作系统鸿蒙系统,据说要大举进军手机市场,替换掉安卓...
手机安卓系统深度清理,解锁手机... 手机里的东西是不是越来越多,感觉就像一个装满了杂物的储物柜?别急,今天就来教你一招——手机安卓系统深...
安卓上的windows系统,融... 你有没有想过,在安卓手机上也能体验到Windows系统的魅力呢?没错,这就是今天我要跟你分享的神奇故...
安卓系统焦点变化事件,Andr... 你知道吗?在安卓系统的世界里,最近发生了一件超级有趣的事情——焦点变化事件。这可不是什么小打小闹,它...