目录
🐲 5. StringBuilder和StringBuffer
🤠 String类 (字符串类型)
在C中是没有字符串类型的,要定义一个字符串,只能通过指针去指向引用它
而在Java中,创造了一个新的类型,那就是String类
通过String可以直接定义一个变量,这个变量可以直接就是字符串
String str = "hello";
🤠 在jdk1.8帮助手册中,可以查看到
🤠 String也有很多构造方法,比如这些
🦄 2.1 字符串构造
通过查看jdk1.8帮助手册,发现String提供的构造方法非常多
🤠下面就看常用的三种吧
public static void main(String[] args) { //1.直接定义一个字符串 String str = "hello"; System.out.println(str); //2.通过new String对象 String str2 = new String("xawl"); System.out.println(str2); //3.通过字符数组进行构造 char[] chars = {'a','b','c'}; String str3 = new String(chars); System.out.println(str3); }
根据在内存中的存储方式,理解一下上面三种构造方法是如何存储的
⚜️先查看一下String源码发现
⚜️ 现在Debug先调试一波,看一下是怎么存储的
🤠 如果要求字符串长度,应该怎么做
//字符串求长度,length()是一个方法 System.out.println(str.length()); //数组求长度 int[] array = {1,2,3}; System.out.println(array.length);
🤠也可以直接给字符串.length() 求长度
System.out.println("hello".length());
🦄 2.2 字符串查找
🤠(1)char charAt(int index),输入位置index,找单个字符
public static void main(String[] args) { String s1 = "hello"; char ch = s1.charAt(1); System.out.println(ch);//e }
⚜️如果说输入一个不合法的位置,去查找这个字符,就会
⚜️如果说需要拿到这些字符去运算呢
public static void main(String[] args) { String s1 = "hello"; for (int i = 0; i < s1.length(); i++) { char ch = s1.charAt(i); System.out.println(ch); } }
🤠(2)int indexOf(int ch) ,返回ch字符第一次出现的位置下标,没有就返回-1
int index = s1.indexOf('l'); System.out.println(index);//2
🤠 (3) int indexOf(int ch, int fromIndex),从fromIndex位置开始找ch字符第一次出现的位置,没有就返回-1
int index = s1.indexOf('l',4); System.out.println(index);//-1 int index1 = s1.indexOf('l',3); System.out.println(index1);//3
🤠(4)int indexOf(String str),找Str字符串第一次出现的位置,返回其字符串首字母下标,没有返回-1
public static void main(String[] args) { String s2 = "helloxawllxh"; int index2 = s2.indexOf("xawl"); System.out.println(index2);//5 }
🤠(5)int indexOf(String str,int formIndex),从formIndex开始,找Str字符串第一次出现的位置,返回其字符串首字母下标,没有返回-1
public static void main(String[] args) { String s2 = "helloxawllxhxawllxh"; int index2 = s2.indexOf("xawl",6); System.out.println(index2);//12 }
🤠(6)int lastIndexOf(int ch),从后往前找字符ch,返回从后往前第一次出现ch字符的下标,没有找到返回-1
public static void main(String[] args) { String s2 = "helloxawllxhxawllxh"; int index3 = s2.lastIndexOf('a'); System.out.println(index3);//13 }
🤠(7)int lastIndexOf(int ch,int fromIndex),从fromIndex开始,从后往前找字符ch,返回从后往前第一次出现ch字符的下标,没有找到返回-1
public static void main(String[] args) { String s2 = "helloxawllxhxawllxh"; int index3 = s2.lastIndexOf('a',7); System.out.println(index3);//6 }
🤠(8)int laseIndexOf(String str),从后往前找,返回字符串str第一次出现位置的首字母下标,没有找到返回-1
public static void main(String[] args) { String s2 = "helloxawllxhxawllxh"; int index4 = s2.lastIndexOf("xawl"); System.out.println(index4);//12 }
🤠(9)int laseIndexOf(String str,int formIndex),从fromIndex开始,从后往前找,返回字符串str第一次出现位置的首字母下标,没有找到返回-1
public static void main(String[] args) { String s2 = "helloxawllxhxawllxh"; int index4 = s2.lastIndexOf("xawl",9); System.out.println(index4);//5 }
总结一下,
输入下标,找单个字符,用charAt方法;
找字符或字符串,需要返回下标
如果是从前往后找,用indexOf方法;
如果是从后往前找,用lastIndexOf方法;
🦄 2.3 字符串截取
🤠从字符串中截取后面字符串的内容,通过substring,
public static void main(String[] args) { String str = "adsasdasdasdasd"; String ret = str.substring(4); System.out.println(ret);//sdasdasdasd }
🤠如果是要截取指定部分内容,可以指定其左右下标范围,但是注意范围是不包括右的[左,右)
public static void main(String[] args) { String str = "adsasdasdasdasd"; String ret = str.substring(4,7);//截取[4,7)里面的字符 System.out.println(ret);//sda }
总结一下,
截取字符串,可以使用subString
🦄 2.4 字符串替换
原来的字符串不变,创建一个新的字符串,替换新字符串中某个字符
🤠 使用replace将字符串中字符进行替换
public static void main(String[] args) { String str1 = "xawlxawlxawlxawl"; String ret = str1.replace('a','B'); System.out.println(ret);//xBwlxBwlxBwlxBwl System.out.println(str1);//xawlxawlxawlxawl }
🤠使用replace或replaceAll将字符串中字符串进行替换
public static void main(String[] args) { String str1 = "xawlxawlxawlxawl"; String ret = str1.replace("xa","B"); String ret1 = str1.replaceAll("xa","B"); System.out.println(ret);//BwlBwlBwlBwl System.out.println(ret1);//BwlBwlBwlBwl System.out.println(str1);//xawlxawlxawlxawl }
🤠 使用replaceFrist将字符串中字符进行替换
public static void main(String[] args) { String str1 = "xawlxawlxawlxawl"; String ret1 = str1.replaceFirst("xa","B"); System.out.println(ret1);//Bwlxawlxawlxawl }
总结一下,
(1)替换字符串中的字符 ,用replace
(2)替换字符串中的字符串 ,用replace或replaceAll
(3)替换字符串中的首个字符串,用replaceFirst
🦄 2.5 字符串拆分
🤠可以将一个完整的字符串按照指定的分隔符,分隔为若干个字符串,用spllit
public static void main(String[] args) { String str1 = "Hello this is xawl rjgc professional"; String[] ret = str1.split(" "); for (String s : ret) { System.out.println(s); } }
🤠将字符串以指定的格式,拆分为limit组
public static void main(String[] args) { String str1 = "Hello this is xawl rjgc professional"; String[] ret = str1.split(" ",3); for (String s : ret) { System.out.println(s); } }
🤠这里还要注意,有些特殊字符(| + * . ,)作为分割符可能无法正确切分, 需要加上转义.
比如," . "点号,如果要识别IP地址中的点号,直接通过split进行拆分是识别不出点号作为分割符的,需要加上转义字符,也就是 \\.
String str2 = "192.188.12.1"; String[] ret1 = str2.split("\\."); for (String s1: ret1) { System.out.println(s1); }
🤠 遇到这些特殊字符,需要加上转义也就是\\,
如果是遇到了\\这个特殊字符,那就要写成\\\\
String str2 = "192\\188\\12\\1"; String[] ret1 = str2.split("\\\\"); for (String s1: ret1) { System.out.println(s1); }
🤠 如果是一个字符串中有多个分隔符,那么用 | 作为连字符
String str3 = "avasda asda&sad"; String[] ret2 = str3.split(" |&"); for (String s2: ret2) { System.out.println(s2); }
🤠 如果是通过多个分隔符来进行多次分割,可以怎么做
可以通过多次for-each循环来split分隔字符串
String str4 = "asda=sdas&dasd=asd"; String[] ret3 = str4.split("="); for (String s : ret3) { String[] s1 = s.split("&"); for (String x : s1) { System.out.println(x); } }
总结一下,
如果要字符串进行拆分,可以用split
但是要注意如果是特殊分隔符,那就需要转义
如果通过多个分隔符对字符串进行分割可以多次for-each循环分割
🦄 2.6 字符串修改
long start = System.currentTimeMillis(); String s = "" ; for (int i = 0; i < 100000; ++i) { s += i; } long end = System.currentTimeMillis(); System.out.println(end - start);
🤠如果是这样的对字符串修改,那就会导致每次修改都会创建新对象,如果这样10W次, 那效率是非常低下的
所以我们应该避免直接对String类型对象进行修改。
如果非要修改那可以使用StringBuffer和StringBuilder进行修改
🦄 2.7 相互转化
🤠(1)数字和字符串转化valueOf
🤠数字转字符串,用String.valueOf(),各种类型的数字都可以传
public static void main(String[] args) { String str = String.valueOf(1234); String str1 = String.valueOf(12.34); System.out.println(str); System.out.println(str1); }
🤠也可以将一个对象转为字符串
定义一个学生类
class Student{ private int age ; public Student(int age) { this.age = age; } @Override public String toString() { return "Student{" + "age=" + age + '}'; }}
直接在valueof里面new Student就可以了
public class Test01 { public static void main(String[] args) { String str2 = String.valueOf(new Student(20)); System.out.println(str2); }}
🤠数字字符串转数字,用Integer.valueOf()(或Integer.valueOf())
⚜️ 直接传数字字符串,就可以转数字了
public static void main(String[] args) { int a = Integer.valueOf("1234"); System.out.println(a);//1234 }
⚜️ 也可以传数字字符串,转成所需进制的数字
public static void main(String[] args) { int a = Integer.valueOf("1234",8); System.out.println(a);//668 }
🤠(2)字母大小写转化toUpperCase()和toLowercase()
⚜️小写字母转大写字母用toUpperCase() ,只转化字符串中的字母,汉字不影响
public static void main(String[] args) { String str3 = "abcdef阿凡达"; String ret = str3.toUpperCase(); System.out.println(ret);//ABCDEF阿凡达 }
⚜️大写字母转小写字母用toLowerCase(),
public static void main(String[] args) { String str4 = "ABCDEF阿凡达"; String ret1 = str4.toLowerCase(); System.out.println(ret1);//abcdef阿凡达 }
🤠这里要注意,大小写转化,不是在原来的字符串中修改,
而是产生一个新的字符串对象进行修改
public static void main(String[] args) { String str4 = "ABCDEF阿凡达"; String ret1 = str4.toLowerCase(); System.out.println(ret1);//abcdef阿凡达 System.out.println(str4);//ABCDEF阿凡达 }
🤠(3)字符串和数组转化toCharArray()和new String()
⚜️字符串转数组用toCharArray()
String str5 = "hello"; char[] chars = str5.toCharArray(); for (char x : chars) { System.out.println(x); }
⚜️数组转字符串直接new String
char[] chars1 = {'a','b','c'}; String str6 = new String(chars1); System.out.println(str6);//abc
🤠(4)格式化输出用String.format()
String str7 = String.format("%d-%d-%d",2022,5,28); System.out.println(str7);//2022-5-28
总结一下,
(1)数字和字符串转化用 String.valueof和Integer.parselnt(或Integer.valueof)
(2)大小写转化用toUpperCase和toLowerCase
(3)字符串和数组转化用toCharArray和new String
(4)格式化输出用format
🦄 2.8 String对象比较
⚜️ 先new上三个字符串
String s1 = new String("hello"); String s2 = new String("hello"); String s3 = new String("world");
⚜️ 如果直接比较
System.out.println(s1 == s2); // false System.out.println(s2 == s3); // false
都会是false,因为new String 是在堆上去创建不同的空间,通过s1,s2,s3,分别去指向他们
(1)也就是对于引用类型,==比较的是地址;
而对于基本类型变量,==比较的是存储的值 ;
🤠 如果说使用equals比较相不相同呢
(2)String类重写了父类Object中equals方法, Object中equals默认按照==比较, String重写equals方法后,就会发生动态绑定
⚜️ 下面使用重写后的equals进行比较
System.out.println(s1.equals(s2));//true System.out.println(s2.equals(s3));//false
🤠 如果说使用compareTo比较大小关系呢
(3)String也重写了compareTo ,可以进行大小关系的比较
System.out.println(s1.compareTo(s1));//0 System.out.println(s2.compareTo(s3));//-15
🤠 如果说使用compareToIgnoreCase比较大小关系呢
🤠 或者使用equalseToIgnoreCase比较大小关系呢
(4)使用compareToIgnoreCase进行比较,可以忽略字母大小写,来进行比较大小关系
使用equalsToIgnoreCase进行比较,可以忽略字母大小写,来进行比较是否相等
public static void main(String[] args) { String s1 = new String("hello"); String s4 = new String("HELLO"); //直接比较大小关系 System.out.println(s1.compareTo(s4));//32 //忽略大小写进行比较 System.out.println(s1.compareToIgnoreCase(s4));//0 //直击比较是否相等 System.out.println(s1.equals(s4));//false //忽略大小写比较是否相等 System.out.println(s1.equalsIgnoreCase(s4));//true }
🦄 2.9 去除字符串左右空格
🤠 去掉字符串中的左右空格,保留中间空格,用trim public static void main(String[] args) { String str = " asdasdasdas "; System.out.println(str.trim());//asdasdasdas }
🦄 3.1 理解池的概率
在java中,字面类型的常量经常频繁使用,而为了使程序的运行速度更快,更节省内存,java给8种基本数据类型和String类都提供了常量池
在java中,为了提高效率,还有很多的“池”,比如内存池,线程池等,
为了节省存储空间和提高程序的运行效率,java中还有这些池:
Class文件常量池,运行时常量池,字符串常量池,
这里主要介绍字符串常量池
🦄 3.2 字符串常量池
字符串常量池在JVM中是StringTable类,实际上是一个固定大小的HashTable
不同JDK版本下字符串常量池位置大小是不同的
JDK版本 | 字符串常量池位置 | 大小设置 |
---|---|---|
Java6 | 方法区 | 固定大小:1009 |
Java7 | 堆 | 默认大小:60013,可自行设置 |
Java8 | 堆 | 最小:1009,可以自行设置 |
🤠 1. 通过字符串常量进行赋值
因为指向的常量池是同一个,所以s1等于s2,返回true
public static void main(String[] args) { String s1 = "hello"; String s2 = "hello"; System.out.println(s1 == s2); // true }
🤠 2.通过new创建String类对象
⚜️ s1和s3的地址是不相同的,所以比较就是false
public static void main(String[] args) { String s1 = "hello"; String s2 = "hello"; String s3 = new String("hello"); System.out.println(s1 == s2); // true System.out.println(s1 == s3); // false }
⚜️ 打个断点调试后,发现这三个引用的数组也是一样的
🤠 3. intern方法
⚜️ 没使用intern方法前
public static void main(String[] args) { char[] ch = new char[]{'a', 'b', 'c'}; String s1 = new String(ch); String s2 = "abc"; System.out.println(s1 == s2);//false }
⚜️ 使用intern方法后
public static void main(String[] args) { char[] ch = new char[]{'a', 'b', 'c'}; String s1 = new String(ch); s1.intern(); String s2 = "abc"; System.out.println(s1 == s2); }
🤠 所以intern的作用是:检查s1所指向的对象在常量池中是否存在,
如果不存在就把当前对象入池;存在就返回常量池中的对象
⚜️ 这里先看一下String,
String类是一个不可变类,即创建String对象后,该对象中的字符串是不可改变的,直到这个对象被销毁。
⚜️ StringBuffer与StringBuilder
StringBuffer与StringBuilder都继承自AbstractStringBuilder类,AbstractStringBuilder中也是使用字符数组保存字符串,是可变类。
并且都提供了一系列插入、追加、改变字符串里的字符序列的方法,它们的用法基本相同
⚜️ 下面可以看一下二者的用法
StringBuilder.append:添加任意类型数据的字符串形式,并返回当前对象自身
public static void main(String[] args) { StringBuilder stringBuilder= new StringBuilder(); stringBuilder.append("hello"); stringBuilder.append(" world"); String s = stringBuilder.toString(); System.out.println(s); }
StringBuilder.reverse 逆置字符串
public static void main(String[] args) { StringBuilder stringBuilder= new StringBuilder(); stringBuilder.append("hello"); stringBuilder.append("world"); stringBuilder.reverse(); System.out.println(stringBuilder);//dlrowolleh }
StringBuffer.apppend
public static void main(String[] args) { StringBuffer stringBuffer= new StringBuffer(); stringBuffer.append("hello"); stringBuffer.append("world"); System.out.println(stringBuffer);//helloworld }
StringBuffer.reverse 逆置字符串
public static void main(String[] args) { StringBuffer stringBuffer= new StringBuffer(); stringBuffer.append("hello"); stringBuffer.append("world"); stringBuffer.reverse(); System.out.println(stringBuffer);//dlrowolleh }
StringBuilder和StringBuffer二者的区别
打开二者append的原码,观察发现
二者相比较,StringBuffer更安全,但并不是说StringBuffer比StringBuilder要更好,
因为StringBuffer的安全是建立在相对来说降低效率和耗费资源的基础之上的。
二者就方法来说,基本都是一样的。
StringBuffer和StringBuilder和String的区别
(1)String内容不可以修改,而StringBuffer与StringBuilder,提供了一系列插入、追 加、 改变字符串里的字符序列的方法,并且修改不产生新的对象,而是在原对象的基 础上修改
(2)就三者效率进行比较
StringBuilder > StringBuffer > String
(3)从安全性和操作数据量来比较
如果要操作的数量比较小,应优先使用String类;
如果是在单线程下操作大量数据,应优先使用StringBuilder类;
如果是在多线程下操作大量数据,应优先使用StringBuffer类。
(4)StringBuffer使用了缓存区,StringBuilder没有使用缓存区,所以没有修改数据的情 况下,多次调用StringBuffer的toString方法获取的字符串是共享底层的字符数组的。
而StringBuilder不是共享底层数组的,每次都生成了新的字符数组
方法 | 作用 |
---|---|
charAt() | 输入下标,找单个字符 |
indexOf() | 从前往后找,找字符或字符串,需要返回下标 |
lastIndexOf() | 从后往前找,找字符或字符串,需要返回下标 |
split() | 对字符串进行拆分,注意特殊字符,需要转义 |
repalce() | 替换字符串中的字符 |
replace()/replaceAll() | 替换字符串中的字符串 |
replaceFrist() | 替换字符串中的首个字符串 |
subString() | 截取字符串 |
String.valueof() | 数字转字符串 |
Integer.parselnt() / Integer.valueof() | 字符串转数字 |
toUpperCase() | 字母小写转大写 |
toLowerCase() | 字母大写转小写 |
toCharArray() | 字符串转数组 |
new String() | 数组转字符串 |
format() | 格式化输出 |
String.equals() | 比较字符串相不相等,返回boolean类型 |
String.compareTo() | 比较字符串大小关系,返回int 类型 |
equlsTolgnoreCase() | 忽略字母大小写,比较是否相等 |
trim() | 去掉字符串中,首尾部空格,保留中间空格 |
来源地址:https://blog.csdn.net/m0_58761900/article/details/125014074