目录
一. 字符串的定义
二. String类中的常用方法
1. 比较两个字符串是否相等(返回值是boolean类型)
2. 比较两个字符串的大小(返回值是int类型)
3. 字符串查找
(1)s1.charAt(index) index:下标,返回字符串的值
(2)s1.indexOf(ch) 从前往后找,返回ch第一次出现时的下标,没有就返回 -1
(3)s1.indexOf(ch,from) 从下标from开始往后找,返回ch第一次出现时的下标,没有就返回 -1
(4)s1.indexOf(str) 在字符串中找字符串str,找到返回下标
(5)s1.indexOf(str,from) 从from下标开始往后找字符串str,找到返回下标
(6)s1.lastIndexOf(ch) 从后往前找,返回ch第一次出现的下标
(7)s1.lastIndexOf(ch,from) 从from开始往前找,返回ch第一次出现的下标
(8)s1.lastIndexOf(str) 从后往前找字符串str,找到返回第一次出现的下标
(9)s1.lastIndexOf(str,from) 从from开始往前找,找到返回第一次出现的下标
4. 转化
(1)String.valueOf(各种类型的变量) —— 其他类型转化成字符串
(2)字符串转化成其他类型
(3)字符串大小写转化
(4)s1.toCharArray() —— 字符串转字符数组【这个方法很重要】
(5)字符数组转字符串 —— 把数组直接扔过去就变成了字符串
5. 字符串替换 —— 返回的是一个新的字符串
6. 字符串拆分
7. 字符串截取(用的非常多)
8. 字符串的其他方法
(1)s1.trim() —— 去掉字符串左右两边的空格
(2)s1.contains(str) —— 字符串s1中是否包含字符串str,返回true 或 false
(3)s1.endsWith(str) —— 判断字符串s1是否以字符串str结尾,返回true 或 false
(4)s1.startsWith(str) —— 判断字符串s1是否以字符串str开始,返回true 或 false
三. 字符串常量池
1. 字符串常量池
题目一:
题目二:
总结:
2. String类对象实例化底层
(1)
(2)
(3)
总结:
3. intern方法
四. 字符串的不可变性
五. 字符串修改
六. StringBuilder和StringBuffer
1. StringBuilder和StringBuffer的特点:
2. StringBuilder和StringBuffer的方法:
3. String、StringBuilder和StringBuffer的不同点:
4. StringBuilder类型的对象和String类型的对象,如何相互转换?
5. 以下分别创建了多少个对象(常量池里都没有)
七. String类oj题
一. 字符串的定义
1. String类中有两个成员:value数组和hash。String内部并不存储字符串本身,字符串保存在char类型的字符数组value中
2. 字符串不以‘\0’结尾
3. 使用 s1.length() 输出字符串的长度
二. String类中的常用方法
String类中的方法,基本上返回的都是一个新的字符串对象,不是在原来上做出改变
1. 比较两个字符串是否相等(返回值是boolean类型)
(1)比较两个字符串是否相等 —— s1.equals(s2)
(2)忽略大小写比较两个字符串是否相等 —— s1.equalsIgnoreCase(s2)
2. 比较两个字符串的大小(返回值是int类型)
因为String类实现了Comparable<String>接口,所以String一定重写了compareTo方法
(1)比较两个字符串的大小 —— s1.compareTo(s2)
(2)忽略大小写比较两个字符串的大小 —— s1.compareToIgnoreCase(s2)
3. 字符串查找
(1)s1.charAt(index) index:下标,返回字符串的值
(2)s1.indexOf(ch) 从前往后找,返回ch第一次出现时的下标,没有就返回 -1
(3)s1.indexOf(ch,from) 从下标from开始往后找,返回ch第一次出现时的下标,没有就返回 -1
(4)s1.indexOf(str) 在字符串中找字符串str,找到返回下标
(5)s1.indexOf(str,from) 从from下标开始往后找字符串str,找到返回下标
(6)s1.lastIndexOf(ch) 从后往前找,返回ch第一次出现的下标
(7)s1.lastIndexOf(ch,from) 从from开始往前找,返回ch第一次出现的下标
(8)s1.lastIndexOf(str) 从后往前找字符串str,找到返回第一次出现的下标
(9)s1.lastIndexOf(str,from) 从from开始往前找,找到返回第一次出现的下标
4. 转化
(1)String.valueOf(各种类型的变量) —— 其他类型转化成字符串
(2)字符串转化成其他类型
(3)字符串大小写转化
小写转大写:s1.toUpperCase()
大写转小写:s1.toLowerCase()
(4)s1.toCharArray() —— 字符串转字符数组【这个方法很重要】
(5)字符数组转字符串 —— 把数组直接扔过去就变成了字符串
5. 字符串替换 —— 返回的是一个新的字符串
(1)s1.replace('oldChar','newChar') 字符oldChar全部替换成newChar
(2)s1.replace(" "," ") 字符串全部替换
(3)s1.replaceAll(" "," ") 字符串全部替换
(4)s1.replaceFirst(" "," ") 替换第一个出现的
6. 字符串拆分
(1)s1.split(拆分符号)
(2)s1.split(拆分符号,拆分成几份)【拆分成几份,即数组中有几个元素,当然不能拆也不能硬拆】
特殊:. \ | * + 等 都得加上转义字符
如: . 【\ 去转义这个 . 了,那么这个 \ 怎么办,还得需要一个 \ 来转义】所以是 \\.
【每个\都需要\去转义,s2里面就有两个\,所以是 \\\\】
\不可能单独存在,因为它会和后面形成转义,就不是\了,只能\\这样存在。\\其实就是一个\。
要是想以一个\进行拆分,可以下面这样,因为是拆分失败,就只能把s1的内容原样输出啦。
如果一个字符串中有多个分隔符,可以用"|"作为连字符
多次拆分:
7. 字符串截取(用的非常多)
(1)s1.substring(index) —— 从index下标开始截取
(2)s1.substring(beginIndex,endIndex) —— 从beginIndex截取到endIndex,左闭右开
8. 字符串的其他方法
(1)s1.trim() —— 去掉字符串左右两边的空格
(2)s1.contains(str) —— 字符串s1中是否包含字符串str,返回true 或 false
(3)s1.endsWith(str) —— 判断字符串s1是否以字符串str结尾,返回true 或 false
(4)s1.startsWith(str) —— 判断字符串s1是否以字符串str开始,返回true 或 false
三. 字符串常量池
1. 字符串常量池
字符串常量池,是存放在堆中的一块区域。底层是一个StringTable的哈希表
只要是双引号引起来的,首先会去字符串常量池检查有没有相同的 ,如果字符串常量池中有,拿常量池的,如果没有,就把字符串存到常量池中,常量池中只存一份。
如:
题目一:
对于s1来说,常量池中没有“hello”这个字符串,所以会在常量池中存一份。给s2赋值“hello”时,常量池中已经存在该字符串了,取的是常量池的同一份,所以结果为true。
题目二:
对于s1来说,常量池中没有“hello”这个字符串,所以会在常量池中存一份。同时,自己new了一个String对象,value中存的是常量池的“hello”的地址(0x12)。给s2赋值“hello”时,常量池中已经存在该字符串了,所以不会再存一遍了,同时,自己又new 了一个String对象,value中存的还是0x12。只不过,s1和s2都是新new了String对象,里面存的是新的地址,所以结果为false。但是,它们value中存的值都是相同的,都指向同一份“hello”。
总结:
构造字符串时,最好不要new一个对象,直接使用字符串常量给引用变量赋值就行,由于字符串常量池的存在,直接赋值的效率更高,而且更节省空间。
2. String类对象实例化底层
(1)
(2)
(3)
会将字符数组ch拷贝一份
总结:
(1)会存到常量池
(2)会存到常量池,堆上还会new一个String对象
(3)堆上new一个数组,对数组进行一次拷贝,然后new一个String对象,让value数组指向拷贝好的数组。
3. intern方法
该方法的作用是当常量池不存在这个对象的时候,会将创建的此对象添加到常量池中。
没用intern之前,s1的对象并不在常量池之中,而是拷贝的ch指向的字符数组。如下图:
所以要想输出true,s1的对象需要在常量池中存一份。
s1调用intern,会将s1所指的对象放到常量池中。那么给s2赋值“abc”时,常量池中已经有"abc"对象了,所以用的是同一份,如下图:
四. 字符串的不可变性
字符串是不可变的,对字符串进行操作,不会在原字符串上进行改变,而是会返回一个新的字符串对象。
五. 字符串修改
字符串是不能修改的,每次修改都会创建新的对象,效率非常低下。
我们通过汇编可以看到,这几行代码,其实创建了许多StringBuilder对象去拼接字符串
还原出来就是下面这个代码:
六. StringBuilder和StringBuffer
StringBuilder和StringBuffer new对象调用构造方法时,会在原来字符串的基础上后面多16个空格。
调用StringBuilder类中的toString方法后,返回一个新的对象,count就是字符串的长度,这个新对象没有多余的16个空格啦。于是StringBuilder就变成String类了。
1. StringBuilder和StringBuffer的特点:
(1)是一个类
(2)不能直接赋值,需要new对象
new对象调用这个构造方法,会在原来字符串的基础上多16个空格,字符串变长了。
(3)StringBuilder和StringBuffer是可变的,拼接后返回的还是这个对象,不会产生新的对象
有返回值,却不需要接收。因为返回的还是这个对象(this),在自身进行了修改。
(4)StringBuilder重写了toString方法,StringBuffer也重写了toString方法
System.out.println(stringBuilder);
首先,会调用StringBuilder重写的toString方法,返回String类型的一个新对象。(假设起名s1)
【调用StringBuilder类中的toString方法:count就是字符串的长度,这个新对象没有多余的16个空格啦】
然后,s1会调用String类中的toString方法,返回this。
所以,最后输出的是字符串“hello”。
2. StringBuilder和StringBuffer的方法:
append:字符串拼接
delete:删除指定范围内的字符,左闭右开
reverse:字符串逆置
3. String、StringBuilder和StringBuffer的不同点:
(1)String的内容不可修改,StringBuilder和StringBuffer的内容可以修改
(2)StringBuffer和StringBuilder大部分功能是相似的
(3)StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
synchronized: 多线程情况下,用来保证线程的安全
4. StringBuilder类型的对象和String类型的对象,如何相互转换?
(1)StringBuilder转String: 调用StringBuilder中的toString方法
(2)String转StringBuilder: 利用StringBuilder的构造方法或append方法
5. 以下分别创建了多少个对象(常量池里都没有)
数组的那个对象不分开算,整体算一个对象
(1):2个,常量池一个,new了一个
(2):6个,常量池2个(“a”和“b”),new的两个,它们两个拼接生成了一个StringBuilder对象,最后,赋值给String类型,会调用StringBuilder的toString方法,toString方法会返回一个新的String对象,即又new了一个对象。总共6个。
七. String类oj题
1. 字符串中的第一个唯一字符
2. 最后一个单词的长度
3. 检测字符串是否为回文
Character类的静态方法:
Character.isDigit(char c) —— 判断字符c是否是数字字符
Character.isletter(char c) —— 判断字符c是否是字母字符
Character.isLowerCase(char c) —— 判断字符c是否是小写字母字符
Character.isUpperCase(char c) —— 判断字符c是否是大写字母字符
Character.isLetterorDigit(char c) —— 判断字符c是否是字母或数字字符