目录

1.了解String类

2.String类常用方法

2.1 字符串构造

2.2 字符串查找

2.3 字符串截取

2.4 字符串替换

2.5 字符串拆分

2.6 字符串修改

2.7 相互转化

2.8 String对象比较

2.9 去除字符串左右空格

3. 字符串常量池

3.1 理解池的概率

3.2 字符串常量池

4. 字符串不可变性

5. StringBuilder和StringBuffer

6. 就本篇所提到的方法进行大致总结


1.了解String类

String类 (字符串类型)

在C中是没有字符串类型的,要定义一个字符串,只能通过指针去指向引用它

而在Java中,创造了一个新的类型,那就是String类

通过String可以直接定义一个变量,这个变量可以直接就是字符串

String str = "hello";

在jdk1.8帮助手册中,可以查看到

String也有很多构造方法,比如这些


2.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);//-1int 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);//xBwlxBwlxBwlxBwlSystem.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);//BwlBwlBwlBwlSystem.out.println(ret1);//BwlBwlBwlBwlSystem.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;}@Overridepublic 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); // falseSystem.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));//trueSystem.out.println(s2.equals(s3));//false

如果说使用compareTo比较大小关系呢

(3)String也重写了compareTo ,可以进行大小关系的比较

System.out.println(s1.compareTo(s1));//0System.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. 字符串常量池

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); // trueSystem.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所指向的对象在常量池中是否存在,

如果不存在就把当前对象入池;存在就返回常量池中的对象


4. 字符串不可变性


5. StringBuilder和StringBuffer

⚜️ 这里先看一下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不是共享底层数组的,每次都生成了新的字符数组


6. 就本篇所提到的方法进行大致总结

方法作用
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()去掉字符串中,首尾部空格,保留中间空格