目录
前言:
1.1、了解字符串构造方法
1.2、求字符串长度(xxx.length())
1.3、isEmpty()方法
1.4、String对象的比较
1.4.1、通过(str1 == str2)来比较,这样比较的是两个引用当中的地址
1.4.2、 boolean equals(Object anObject)方法:比较两个引用所指向的对象里面的内容是否一致
1.4.3、 int compareTo(String s)方法:用来比较两个字符串的大小
1.4.4、int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写,进行比较
1.5、字符串查找
1.5.1、char charAt(int index)方法:查找index下标上的字符
1.5.2、int indexOf(int ch)方法:找字符串中c第一次出现的位置,没有返回-1
1.5.3、int indexOf(int ch,int fromIndex)方法:从指定下标(fromIndex)开始查找字符c第一次出现的位置(下标)
1.5.4、 int indexOf(String str)方法:查找字符串中某一串字符串(abcd)出现的位置,返回这个字符串的第一个字母的下标,没有返回-1
1.5.5、int lastIndexOf(int ch):默认从后往前找,找到返回下标,没找到返回-1
1.5.6、int lastIndexOf(int ch, int fromIndex)方法:从指定位置(fromIndex)开始找,从后往前字母(a)第一次出现的位置。
1.6、字符串的转换
1.6.1、数字转字符串:xxx.valueOf()
1.6.2、字符串转数字 :Integer.paresInt(str1)
1.6.3、字符串小写转大写:xxx.toUpperCase();
1.6.4、字符串大写转小写:xxx.toLoweCase();
1.6.5、字符串转数组:xxx.toCharArray();
1.6.6、格式化输出
1.7、字符串的替换
1.7.1、替换指定的字母:xxx.replace();
1.7.2、 替换所有指定的内容(xxx.replaceAll)
1.7.3、替换首个所指的内容(xxx.replaceFirst)
1.8、字符串的拆分
1.8.1、String[] split(String regex):将字符串全部拆分
1.8.2、 String[] split(String regex, int limit) :将字符串以指定的格式,拆分为limit组
1.8.3、拆分IP地址:有一些特殊字符作为分割符可能无法正常切分,需要加上转义。
1.8.4、多次拆分
1.9、字符串的截取
1.9.1、String substring(int beginIndex) :从指定位置开始截取所有字符
1.9.2、String substring(int beginIndex, int endIndex) :截取某个区域内的内容
1.10、String trim():去掉字符串中的最外侧的空格,保留中间空格
1.11、字符串的不可变性
1.12、字符串的修改
2、StringBulider和StringBuffer
2.1、StringBulider的学习
2.1.1、StringBuilder类的append方法
2.1.2、Stringbuilder类当中的方法介绍
2.2、String、StringBuilder、StringBuffer的区别
2.3、来看一道面试题
2.4、习题
前言:
在c语言中,使用字符串,一般使用字符数组和字符串指针,它没有一个专门的类。而在Java中设计出专门的类,将数据和操作数据的方法放在一个类当中,这样符合Java的面向对象的思想。
🏆创建一个类对最终目的就是实例化对象,所以在学习一个类的时候一定是从它的构造方法开始学起。
1.1、了解字符串构造方法
String类提供的构造方法有很多,常用的就一下三种:
1️⃣、使用常量串构造
2️⃣、直接newString对象
3️⃣、使用字符数组经行构造
public class Test {
public static void main(String[] args) {
//使用常量串构造
String str1 = "hello";
System.out.println(str1);
//直接newString对象
String str2 = new String("hello");
System.out.println(str2);
}
}
String类是引用类型,所以这两种写法的本质是一样的,区别就是使用常量串简化了直接newString对象。
public class Test {
public static void main(String[] args) {
//字符数组
char[] values = {'a','v','c','d'};
//这里new String对象,是调用构造方法,将字符数组转化成为字符串。
String str3 = new String(values);
System.out.println(str3);
}
}
当然,想了解String类更多的构造方法,可以选中String按住Ctrl+点击鼠标左键,然后再点击左下角的Structure,来查看String类的构造方法。
❗❗❗【注意】
1、String是引用数据类型,内部并不存储字符串本身,String类有两个成员属性,在创建String类的时候,不论调用有参还是无参构造方法,都会给value属性赋值。
🌈两个成员属性:value hash
2、通过调试上述的代码,我们可以看见,字符串结束的时候,并不像C语言一样,使用\0来结束。
上述代码,可以画图理解:
String是一个类,那么就有很多方法,那么现在来了解一下他的方法
1.2、求字符串长度(xxx.length())
public class Test {
public static void main(String[] args) {
String str1 = "hello";
System.out.println(str1.length());
//通过调用String类当中的lenght()方法,就可以求出字符串的长度
}
相比于数组求长度(array.length)
public class Test {
public static void main(String[] args) {
int[] array = {1,2,3,4};
System.out.println(array.length);
}
💥字符串求长度调用的是length()方法,而数组求长度调用的类似于一个属性(array.length),所以在使用的时候要分清是否要加()
1.3、isEmpty()方法
表示判断引用所指向的对象里面的字符串长度是否为0,是,返回true,不是,返回false。
public class Test {
public static void main(String[] args) {
String str2 = "";
System.out.println(str2.length());//0
//下面两个isEmpty表示的空,是字符串长度为空
System.out.println(str2.isEmpty());//true
//null:表示str3指向的引用为空,表示str3不指向任何对象
String str3 = null;
}
❗❗❗注意:
在Java中“”引起来的也是String类型的对象
// 打印"hello"字符串(String对象)的长度 System.out.println("hello".length());
在调用上述两个方法时,一定是一个字符串类型,不一定是一个变量,它也可以是一个常量。
1.4、String对象的比较
字符串的比较有两种情况:
1️⃣相不相同
2️⃣大小
1.4.1、通过(str1 == str2)来比较,这样比较的是两个引用当中的地址
public class Test {
public static void main(String[] args) {
String str1 = "hello";
String str2 = "abcd";
System.out.println(str1 == str2);
//比较的是两个引用当中的地址,结果一定是错的
}
1.4.2、 boolean equals(Object anObject)方法:比较两个引用所指向的对象里面的内容是否一致
public class Test {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2));
}
✨拓展:equals也可以忽略大小写进行比较内容是否一致
public class Test {
public static void main(String[] args) {
String str1 = new String("HEllo");
String str2 = new String("hello");
//忽略大小写进行比较内容是否一致,返回true或false
System.out.println(str1.equalsIgnoreCase(str2));
}
}
1.4.3、 int compareTo(String s)方法:用来比较两个字符串的大小
compareTo()方法,按字典序进行比较大小
字典序:字符大小的顺序
public class Test {
public static void main(String[] args) {
String str1 = new String("hello");
String str2 = new String("abcd");
//比较两个引用所指向的对象的内容的大小
System.out.println(str1.compareTo(str2));
}
当str1>str2时,返回一个正数
当str1<str2时,返回一个负数
当str1=str2时,返回0
str1:调用这个方法的引用,str2:作为参数传给这个方法的引用
这里可以了解一下这个方法的返回值
所以上述代码,比较结果为7,h比a大7,返回了差值。
✨字符串比较存在这样的情况
public class Test {
public static void main(String[] args) {
String str1 = new String("helloabc");
String str2 = new String("hello");
//比较两个引用所指向的对象的内容的大小
System.out.println(str1.compareTo(str2));
}
1.4.4、int compareToIgnoreCase(String str)方法:与compareTo方式相同,但是忽略大小写,进行比较
public class Test {
public static void main(String[] args) {
String str1 = new String("Hello");
String str2 = new String("hello");
//忽略大小写进行比较
System.out.println(str1.compareToIgnoreCase(str2));
}
1.5、字符串查找
方法 | 功能 |
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch,int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str,int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch,int fromIndex) | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返回-1 |
int lastIndexOf(String str) | 从后往前找,返回str第一次出现的位置,没有返回-1 |
int lastIndexOf(String str,int fromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返回-1 |
1.5.1、char charAt(int index)方法:查找index下标上的字符
public class Test {
public static void main(String[] args) {
String str1 = "hello";
for (int i = 0; i < str1.length(); i++){
//将变量i作为charAt()方法的参数,被charAt()方法的index参数接收,每循环一次输出一个字母
System.out.println(str1.charAt(i));
}
}
1.5.2、int indexOf(int ch)方法:找字符串中c第一次出现的位置,没有返回-1
public class Test {
public static void main(String[] args) {
String str1 = "abcabcabcabcde";
//直接返回c字母在数组中的下标
System.out.println(str1.indexOf('c'));
}
1.5.3、int indexOf(int ch,int fromIndex)方法:从指定下标(fromIndex)开始查找字符c第一次出现的位置(下标)
public class Test {
public static void main(String[] args) {
String str1 = "abcabcabcabcde";
//从指定的下标为6的位置开始找c第一次出现的位置(下标)
System.out.println(str1.indexOf('c',6));
}
1.5.4、 int indexOf(String str)方法:查找字符串中某一串字符串(abcd)出现的位置,返回这个字符串的第一个字母的下标,没有返回-1
public class Test {
public static void main(String[] args) {
String str1 = "abcabcabcabcde";
System.out.println(str1.indexOf("abcd"));
}
}
1.5.5、int lastIndexOf(int ch):默认从后往前找,找到返回下标,没找到返回-1
public class Test {
public static void main(String[] args) {
String str1 = "abcabcabcabcde";
//查找的时候,是从后往前找,但是返回下标的时候,是从前往后数
System.out.println(str1.lastIndexOf('a'));
}
}
1.5.6、int lastIndexOf(int ch, int fromIndex)方法:从指定位置(fromIndex)开始找,从后往前字母(a)第一次出现的位置。
public class Test {
public static void main(String[] args) {
String str1 = "abcabcabcabcde";
//查找的时候,是从后往前找,但是返回下标的时候,是从前往后数
System.out.println(str1.lastIndexOf('a',7));
}
1.6、字符串的转换
1.6.1、数字转字符串:xxx.valueOf()
public class Test{
public static void main(String[] args) {
//数字转字符串
String str1 = String.valueOf(123);
System.out.println(str1);
}
}
1.6.2、字符串转数字 :Integer.paresInt(str1)
public class Test{
public static void main(String[] args) {
String str2 = "12345";
//字符串转数字
int data = Integer.parseInt(str2);
System.out.println(data);
}
以上这两种转换只限定于,数字样式的字符串,将字符串和数字之间相互转换,不能字母和数字之间转换,这样编译器会报错。
1.6.3、字符串小写转大写:xxx.toUpperCase();
public class Test{
public static void main(String[] args) {
String str1 = "abcd";
//字符串小写转大写
System.out.println(str1.toUpperCase());
}
1.6.4、字符串大写转小写:xxx.toLoweCase();
public class Test{
public static void main(String[] args) {
String str2 = "ABCD";
//字符串大写转小写
System.out.println(str2.toLowerCase());
}
1.6.5、字符串转数组:xxx.toCharArray();
public class Test{
public static void main(String[] args) {
String str1 = "abcdef";
//字符串转数组,因为toCharArray()方法的返回值是char[]类型,所以用char[]类型的数组接收
char[] array = str1.toCharArray();
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
}
}
1.6.6、格式化输出
public class Test{
public static void main(String[] args) {
String s = String.format("%d-%d-%d",2022,12,25);
System.out.println(s);
}
}
1.7、字符串的替换
1.7.1、替换指定的字母:xxx.replace();
public class Test{
public static void main(String[] args) {
String str1 = "aaaaabbbbbddddcccc";
//将字符串中的a字母全都替换成p
String ret1 = str1.replace('a','p');
System.out.println(ret1);
}
}
1.7.2、 替换所有指定的内容(xxx.replaceAll)
public class Test{
public static void main(String[] args) {
String str2 = "abaababababcd";
String ret2 = str2.replaceAll("ab","ooo");
System.out.println(ret2);
}
}
1.7.3、替换首个所指的内容(xxx.replaceFirst)
public class Test{
public static void main(String[] args) {
String str1 = "aaaaabbbbbddddcccc";
String ret3 = str1.replaceFirst("ab","999");
System.out.println(ret3);
}
}
✨ 拓展:上述的replaceAll和replaceFirst方法,也可以将字符串中的某个字符替换成空格,还是某些字符都是可以的。但是replace方法是不能实现的
public class Test{
public static void main(String[] args) {
String str1 = "aaaaabbbbbddddcccc";
String ret3 = str1.replaceFirst("ab"," # ");
System.out.println(ret3);
}
}
🎉🎉总结:由于字符串是不可变对象,所以上述的字符串的替换和字符串的转化,都没有修改当前的字符串,而是产生一个新的字符串,对其进行修改。
1.8、字符串的拆分
字符串的拆分有两种方法:
1.8.1、String[] split(String regex):将字符串全部拆分
public class Test{
public static void main(String[] args) {
String str = "how are you";
//按空格拆分,将拆分后的字符串用字符串数组进行接收
String[] strs = str.split(" ");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
}
1.8.2、 String[] split(String regex, int limit) :将字符串以指定的格式,拆分为limit组
public class Test{
public static void main(String[] args) {
String str = "how are you";
//按照空格拆分,拆分成两组
String[] strs = str.split(" ",2);
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
1.8.3、拆分IP地址:有一些特殊字符作为分割符可能无法正常切分,需要加上转义。
【注意事项】
- 字符"|" ,"*","+"都得加上转义字符,前面加上"\\".
- 而如果"\",那么就得写成"\\\\".
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符。
1、
public class Test{
public static void main(String[] args) {
String str = "192.168.1.1";
//按照.拆分,要添加转义字符\,但是这里添加了两个\,原因在于先将\转义,在转义.
String[] strs = str.split("\\.");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
2、
public class Test{
public static void main(String[] args) {
String str = "192\\168\\1\\1";
//在写字符串的时候,不能单独写一个\,因为这样和后面的数组形成了转义必须写\\
//按照\拆分,在写的时候,先要将\转义,再转义\\,所以这里就要写\\\\
String[] strs = str.split("\\\\",2);
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
3、
public class Test{
public static void main(String[] args) {
String str = "192&168@1=1";
//字符串被多个分割符隔开,想要将字符串按照这些分割符拆分,那么可以使用连字符将这些分隔符写在一起
String[] strs = str.split("&|@|=");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
}
1.8.4、多次拆分
public class Test{
public static void main(String[] args) {
String str = "name=zhangsan&age=18";
//这个字符串中有两部分,名字和年龄,先将她两拆分
String[] strs = str.split("&");
for (int i = 0; i < strs.length; i++) {
//拆分成两个数组后,再用=拆分
String[] string = strs[i].split("=");
for (String s:string){
System.out.println(s);
}
}
}
}
1.9、字符串的截取
1.9.1、String substring(int beginIndex) :从指定位置开始截取所有字符
public class Test{
public static void main(String[] args) {
String str = "abcdefgh";
//从第二个字母开始截取后面所有字母
String s = str .substring(2);
System.out.println(s);
}
1.9.2、String substring(int beginIndex, int endIndex) :截取某个区域内的内容
public class Test{
public static void main(String[] args) {
String str = "abcdefgh";
//表示包含0下标的字符,不包含6下标的字符
String s = str .substring(0,6);//他是一个前闭后开区间的写法[)
System.out.println(s);
}
}
注意事项:
1、索引从0开始
2、注意前闭后开区间的写法。
3、 字符串的拆分和截取,都不是再原字符串上操作的,都是在新产生的字符串上操作的。
1.10、String trim():去掉字符串中的最外侧的空格,保留中间空格
public class Test{
public static void main(String[] args) {
String str = " hello abcd ";
System.out.println(str);
//去掉最外侧的空格,保留中间的空格
String ret = str.trim();
System.out.println(ret);
}
}
1.11、字符串的不可变性
public class Test{
public static void main(String[] args) {
String str1 = "abcd";
String str2 = new String("abcd");
String str3 = "abcd";
System.out.println(str1 == str2);
System.out.println(str1 == str3);
}
❗❗❗【纠正错误】
上述这副图在这里只是用作理解上述代码中为什么str1==str3,字符串常量池还没有讲解,所以这幅图是错误的,举例来说
1、String str1 = "abc";从下面这副图来看,他创建了一个String对象(value)和一个char数组对象(abc).
2、String str2 = new String(abc);从下面的图来看,它创建了两个String对象(value)和一个char数组对象(abc);
这里涉及到常量池的概念,小编还没学习常量池的内容,所以这里就不讲解了。
字符串为什么有不可变性?
- 给String类的引用赋值字符串后,在内存中字符串是以字符数组的形式保存的。
- String类当中的value[ ] 属性,是被private修饰的,也就是说value[ ] 是被封装的。
- 被封装了之后,因该要设置公开方法get和set方法,来得到value[ ] ,并且可以修改value[ ]所指向的数组中的值。
- 但是在String类当中,并没有给出公开的方法让我们得到value[ ]属性。得不到value[ ]引用,所以他指向的数组中的内容不能被修改,所以字符串具有不可变性 。
总结:
1、String类被final修饰,表明该类不能被继承
2、value被final修饰,表明value不能引用其他对象(指向不可变),即不能引用其他字符数组,但是其引用空间中的内容可以修改。
为什么String要设计成不可变的?(不可变对象的好处是什么?)
- 方便实现字符串池,如果String可变,那么对象池就需要考虑写时拷贝的问题了。
- 不可变对象是线程安全的。
- 不可变对象更方便缓存hash code,作为key时可以更高效的保存到HashMap中
1.12、字符串的修改
注意:尽量避免直接对String类型对象进行修改,因为String类是不能修改的,所有的修改都会创建新对象,效率非常低下。
public class Test {
public static void main(String[] args) {
String str = "hello";
str += "abc";
System.out.println(str);
}
}
通过反汇编来看一下,这种方式在中间创建了很多对象
模拟一下上述反汇编的代码:
public class Test {
public static void main(String[] args) {
String str = "hello";
// 这里4句代码相当于上面代码的str += "abc";
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.append(str);
stringBuilder.append("abc");
// 这里调用toString方法的作用是,在拼接完成之后,有一个新的String对象
str = stringBuilder.toString();
System.out.println(str);
}
}
那么设想一下,每拼接一次,调用上述的4句代码,那么在代码编写时,写一个循环,那么每循环一次,调用这4句代码,就造成了代码效率非常低下。
总结:
所以在循环当中不建议使用+对字符串进行拼接。因为这样的写法,会产生很多的临时对象,造成代码效率低下。如果要修改建议尽量使用StringBuffer或者StringBulider
2、StringBulider和StringBuffer
2.1、StringBulider的学习
由于String的不可更改特性,为了方便字符串的修改,Java中有提供了StringBulider和StringBuffer类,这两个类大部分功能时相同的
通过上述图片可以看见,StringBuilder类有即有参构造方法,也有无参构造方法。
2.1.1、StringBuilder类的append方法
❓❓那么StringBuilder类对字符串进行拼接,会是什么样的那?
🕖先来看一下append方法的源码:
🕕利用append方法对字符串进行拼接
public class Test {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("abc");
System.out.println(stringBuilder);
stringBuilder.append("123").append(10);
stringBuilder.append(19.0);
System.out.println(stringBuilder);//此时不会产生多余的临时对象,
//他永远返回的是当前对象,所有的修改都在当前对象
}
}
2.1.2、Stringbuilder类当中的方法介绍
方法 | 说明 |
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字符 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
String substring(int start,int end) | 将[start, end)范围内的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
❗❗❗总结:从上述例子可以看出:String和StringBuilder最大的区别在于String的内容无法修改,而StringBuilder的内容可以修改。频繁修改字符串可以考虑使用StringBuilder。
❗❕❗注意:String和StringBuilder类不能直接转换。如果想要相互转换,可以采用如下原则:
- String变为StringBuilder:利用StringBuilder的构造方法或append()方法。
- StringBuilder变为String:调用toString()方法。
//通过stringBuilder来调用toString方法,达到将StringBuilder类型对象转换为String类型对象 public class Test { public static void main(String[] args) { StringBuilder stringBuilder = new StringBuilder("abc"); String ret = stringBuilder.toString(); } }
//通过stringBuilder调用构造方法或者append()方法,将String类型转换为StringBuilder类型 public class Test { public static void main3(String[] args) { StringBuilder stringBuilder = new StringBuilder("abc"); System.out.println(stringBuilder); stringBuilder.append("123"); System.out.println(stringBuilder); } }
2.2、String、StringBuilder、StringBuffer的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作
2.3、来看一道面试题
以下两串代码分别创建了几个String对象【前提:不考虑常量池之前是否存在】
String str = new String("ab"); // 会创建多少个对象
String str = new String("a") + new String("b"); // 会创建多少个对象
1️⃣第一句:创建了2个对象。
- 因为字符串是一个对象,
- 而又new了一个对象,所以有两个对象。
2️⃣第二句:创建了5个对象。
- 因为字符串是一个对象,
- 而又new了两个对象,
- 又因为在进行字符串的拼接,这样会创建一个StringBuilder类型的对象,
- 在拼接完成之后,又会通过StringBuilder类型的对象调用toString方法,这样又创建了一个String对象。
- 又因为问的是创建了几个String对象,所以StringBuilder对象在这里就不算了。
- 为什么StringBuilder调用的toString方法创建的对象在这里可以算一个String对象?toString方法创建的对象是String类型的,所以在这里算。
2.4、习题
1、字符串中的第一个唯一字符
给定一个字符串s,找到他的第一个不重复的字符,并返回他的索引。如果不存在,则返回-1。
要求:字符串s只包含小写字母。
public class Test {
public int firstUniqChar(String s) {
int[] count = new int[26];
//统计每个字符出现的次数
for(int i = 0; i < s.length(); ++i){
char ch = s.charAt(i);
count[ch - 'a']++;
}
//找第一个只出现一次的字符
for(int i = 0; i < s.length(); ++i){
char ch = s.charAt(i);
//通过for循环遍历,并且通过if判断每一个字母在上一轮的fou循环中计数的情况(是否只出现过一次,若第一个字母计数>1,那么就判断下一个字母,直到找到计数为一的字母,并返回该字母)
if(count[ch - 'a'] == 1){//用ch - 'a'用字母的ASCII的减去97,得到字母在数组中的下标。
return i;
}
}
return -1;
}
2、最后一个单词的长度
输出一个正数,表示输入字符串最后一个单词的长度。
import java.util.Scanner;
public class Test {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
while(in.hasNextLine()){
String str = in.nextLine();
int index = str.lastIndexOf(" ");//最后一个空格开始
String ret = str.substring(index+1);//从最后一个空格+1的位置开始,向后计算字符串的长度
System.out.println(ret.length());
}
}
}
3、检测一个字符串是否为回文字符串
如果在将所有大写字符转换为小写字符,并移除所有非字母数字字符之后短语正着读和反着读都一样。则可认为该短语是一个回文串。
字母和数字都属于数字字符。
要求 :给你一个字符串s,如果他是回文串,返回true;否则,返回false.
public class Test {
public boolean isPalindrome(String s){
s = s.toLowerCase();//将大写字母转换为小写
int left = 0;//从左边开始的下标
int right = s.length()-1;//从右边开始的下标
while(left < right){
while(left < right && !isValidChar(s.charAt(left))){
left++;
}
while(left < right && !isValidChar(s.charAt(right))){//条件是左边下标小于右边下标,并且来两边要是有效字符。
right -- ;
}
//判断如果左边字母不等于右边字母,返回false,两边字母相等,左边向前挪一位,右边向前挪一位。
//每个字母判断完成之后,都相等,返回true。
if(s.charAt(left) !=s.charAt(right)){
return false;
}else{
left++;
right--;
}
}
return true;
}
//判断他是否为有效字符
private boolean isValidChar(char ch){
if(ch >= '0' && ch <= '9'|| ch <= 'a'&& ch <= 'z'){
//上边语句可以优化为
//if(Character.isDigit(ch)||Character.isLetter(ch))
//isDigit()判断是否为数字 isLetter()判断是否为字母
return true;
}
return false;
}
}