目录
- 一、构造器方法
- 二、String与字节数组的转换(编码与解码)
- 1、字符串 --> 字节数组:(编码)
- 2、字节数组 --> 字符串:(解码)
- 3、iso-8859-1的特殊用法
- 4、byte数组的数字表示
- 三、常用API
- 1、常用方法
- 2、查找
- 3、字符串截取
- 4、和字符/字符数组相关
- 5、开头与结尾
- 6、替换
- 四、常见算法题
- 1、模拟一个trim方法,去除字符串两端的空格
- 2、将一个字符串进行反转。将字符串中指定部分进行反转。比如“ab`cdef`g”反转为”ab`fedc`g”
- 3、获取一个字符串在另一个字符串中出现的次数。比如:获取“ ab”在 “abkkcadkabkebfkabkskab” 中出现的次数
- 4、获取两个字符串中最大相同子串。比如:str1 = "abcwerthelloyuiodef“;str2 = "cvhellobnm"
- 五、StringBuffer和StringBuilder
- 1、StringBuffer与StringBuilder的理解
- 2、StringBuilder、StringBuffer的API
- 3、效率测试
一、构造器方法
public String()
:初始化新创建的 String对象,以使其表示空字符序列String(String original)
: 初始化一个新创建的String
对象,使其表示一个与参数相同的字符序列;换句话说,新创建的字符串是该参数字符串的副本public String(char[] value)
:通过当前参数中的字符数组来构造新的Stringpublic String(char[] value,int offset, int count)
:通过字符数组的一部分来构造新的String
举例:
//字面量定义方式:字符串常量对象
String str = "hello";//构造器定义方式:无参构造
String str1 = new String();//构造器定义方式:创建"hello"字符串常量的副本
String str2 = new String("hello");//构造器定义方式:通过字符数组构造
char chars[] = {'a', 'b', 'c','d','e'};
String str3 = new String(chars); // abcde
String str4 = new String(chars,0,3); // abc
二、String与字节数组的转换(编码与解码)
1、字符串 --> 字节数组:(编码)
public byte[] getBytes()
:使用平台的默认字符集将此 String 编码为 byte 序列,并将结果存储到一个新的 byte 数组中public byte[] getBytes(String charsetName)
:使用指定的字符集将此 String 编码到 byte 序列,并将结果存储到新的 byte 数组
2、字节数组 --> 字符串:(解码)
String(byte[])
:通过使用平台的默认字符集解码指定的 byte 数组,构造一个新的 String- String(byte[],int offset,int length) :用指定的字节数组的一部分,即从数组起始位置offset开始取length个字节构造一个字符串对象
String(byte[], String charsetName )
或 new String(byte[], int, int,String charsetName ):解码,按照指定的编码方式进行解码
举例:
byte[] b_gbk = "中".getBytes("gbk");
byte[] b_utf8 = "中".getBytes("utf-8");
byte[] b_iso88591 = "中".getBytes("iso-8859-1");
- 将返回"中"这个汉字分别在gbk、utf-8、iso-8859-1编码下的字节数组表示
- 此时b_gbk的长度为2,b_utf8的长度为3,b_iso88591的长度为1
- 与getBytes()方法相反,可以通过new String(byte[], charsetName)方法用指定的字符集来还原这个"中"字,如:
String s_gbk = new String(b_gbk, "gbk");
String s_utf8 = new String(b_utf8, "utf-8");
String s_iso88591 = new String(b_iso88591, "iso-8859-1");
- 打印出s_gbk、s_utf8、s_iso88591可以看到,s_gbk和s_utf8都是"中",而s_iso88591是一个乱码
- 这是因为iso-8859-1的编码表中,根本就没有包含汉字
- 因此"中".getBytes(“iso-8859-1”)得到的是"?“的字节数组表示
- 再通过new String(b_iso88591, “iso-8858-1”)还原得到的是”?"
3、iso-8859-1的特殊用法
- 有时候,为了让中文字符适应某些特殊要求(如http header要求其内容必须是iso-8859-1编码)
- 可能会通过将中文字符按照字节方式来编码的情况,如:
String s_iso88591 = new String("中".getBytes("utf-8"), "iso-8859-1");
- 得到的字符串s_iso88591实际上是三个在iso-8859-1中的字符,在将这些字符传送到目的地后,再通过相反的方式,即:
String s_utf8 = new String(s_iso88591.getBytes("iso-8859-1"), "utf-8");
- 从而得到正确的中文汉字"中",这样就既保证了遵守协议规定,也支持了中文
4、byte数组的数字表示
byte[] b = "中".getBytes("utf-8");
for(int i=0; i<b.length; i++) {System.out.println(b[i]);
}
输出:
-28
-72
-83
- 因为"中"的utf-8编码为三个字节,分别是E4 B8 AD
- 以E4为例,换成二进制即为:1110 0100
- 该二进制数将以补码存储在内存中,最高位被视为符号位
- 因此原码是:1110 0100(补码) -> 1001 1011(反码) -> 1001 1100(原码)
- 即-(16+8+4)=-28
三、常用API
1、常用方法
- boolean isEmpty():字符串是否为空
- int length():返回字符串的长度
- String concat(xx):拼接
- boolean equals(Object obj):比较字符串是否相等,区分大小写
boolean equalsIgnoreCase(Object obj)
:比较字符串是否相等,不区分大小写int compareTo(String other)
:比较字符串大小,区分大小写,按照Unicode编码值比较大小- int compareToIgnoreCase(String other):比较字符串大小,不区分大小写
String toLowerCase()
:将字符串中大写字母转为小写String toUpperCase()
:将字符串中小写字母转为大写- String trim():去掉字符串前后空白符
- public String intern():结果在常量池中共享
@Test
public void test1(){String s1 = "hello";String s2 = "HellO";System.out.println(s1.equals(s2));System.out.println(s1.equalsIgnoreCase(s2));String s3 = "abcd";String s4 = "adef";System.out.println(s3.compareTo(s4));String s5 = "abcd";String s6 = "aBcd";System.out.println(s5.compareTo(s6));System.out.println(s5.compareToIgnoreCase(s6));String s7 = "张ab";String s8 = "李cd";System.out.println(s7.compareTo(s8));String s9 = " he llo ";System.out.println("****" + s9.trim() + "*****");
}
2、查找
- boolean contains(xx):是否包含xx
int indexOf(xx)
:从前往后找当前字符串中xx,即如果有返回第一次出现的下标,要是没有返回-1int indexOf(String str, int fromIndex)
:返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始int lastIndexOf(xx)
:从后往前找当前字符串中xx,即如果有返回最后一次出现的下标,要是没有返回-1int lastIndexOf(String str, int fromIndex)
:返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
@Test
public void test2(){String s1 = "教育尚硅谷教育";System.out.println(s1.contains("硅谷")); // trueSystem.out.println(s1.indexOf("教育")); // 0System.out.println(s1.indexOf("教育",1)); // 5System.out.println(s1.lastIndexOf("教育")); // 5System.out.println(s1.lastIndexOf("教育",4)); // 0
}
3、字符串截取
String substring(int beginIndex)
:返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串String substring(int beginIndex, int endIndex)
:返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串
@Test
public void test3(){String s1 = "教育尚硅谷教育";System.out.println(s1.substring(2)); // 尚硅谷教育System.out.println(s1.substring(2,5));//[2,5) // 尚硅谷
}
4、和字符/字符数组相关
char charAt(index)
:返回[index]位置的字符char[] toCharArray()
: 将此字符串转换为一个新的字符数组返回- static String valueOf(char[] data) :返回指定数组中表示该字符序列的 String
- static String valueOf(char[] data, int offset, int count) : 返回指定数组中表示该字符序列的 String
@Test
public void test4(){String s1 = "教育尚硅谷教育";System.out.println(s1.charAt(2)); // 尚// valueOf和copyValueOf源码一模一样的,就是用char数组new String(char[] ch)String s2 = String.valueOf(new char[]{'a', 'b', 'c'}); // abcString s3 = String.copyValueOf(new char[]{'a', 'b', 'c'}); // abc
}
5、开头与结尾
boolean startsWith(xx)
:测试此字符串是否以指定的前缀开始boolean startsWith(String prefix, int toffset)
:测试此字符串从指定索引开始的子字符串是否以指定前缀开始boolean endsWith(xx)
:测试此字符串是否以指定的后缀结束
@Test
public void test5(){String s1 = "教育尚硅谷教育";System.out.println(s1.startsWith("教育a")); // falseSystem.out.println(s1.startsWith("教育",5)); // true
}
6、替换
String replace(char oldChar, char newChar)
:返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。 不支持正则String replace(CharSequence target, CharSequence replacement)
:使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串String replaceAll(String regex, String replacement)
:使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串String replaceFirst(String regex, String replacement)
:使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串
@Test
public void test6(){String s1 = "hello";String s2 = s1.replace('l', 'w');System.out.println(s1); // helloSystem.out.println(s2); // hewwoString s3 = s1.replace("ll", "wwww");System.out.println(s3); // hewwwwo
}
四、常见算法题
1、模拟一个trim方法,去除字符串两端的空格
思路:查看字符串前缀后缀是否存在“ ”,去除后继续判断
public static String trimStr(String str) {while (str.startsWith(" ") || str.endsWith(" ")) {if (str.startsWith(" ")) {str = str.substring(1);}if (str.endsWith(" ")) {str = str.substring(0, str.length() - 1);}}return str;
}
2、将一个字符串进行反转。将字符串中指定部分进行反转。比如“abcdef
g”反转为”abfedc
g”
方法一思路:字符串转换为字符数组,从指定角标到结束角标,互换数据
public static String reversalStr(String str, int fromIndex, int toIndex) {char[] charArray = str.toCharArray();for (int i = fromIndex, j = toIndex; i < j; i++, j--) {char temp = charArray[i];charArray[i] = charArray[j];charArray[j] = temp;}return new String(charArray);
}
方法二思路:截取前中后三个字符串,中是需要反转的,从新拼接,拼接中字符串时候,从后开始拼接
public static String reversalStr2(String str, int fromIndex, int toIndex) {String strReturn = str.substring(0, fromIndex);for (int i = toIndex; i >= fromIndex; i--) {strReturn += str.charAt(i);}strReturn += str.substring(toIndex + 1);return strReturn;
}
3、获取一个字符串在另一个字符串中出现的次数。比如:获取“ ab”在 “abkkcadkabkebfkabkskab” 中出现的次数
思路:获取字符首次出现的角标,然后从出现的位置继续向后找
public static int getCount(String str, String subStr) {int count = 0;int index = str.indexOf(subStr);while (index != -1) {index = str.indexOf(subStr, index + subStr.length());count++;}return count;
}
4、获取两个字符串中最大相同子串。比如:str1 = "abcwerthelloyuiodef“;str2 = “cvhellobnm”
思路:从小字符串下手,通过不同长度截取
public static String getMaxStr(String str1, String str2) {for (int i = 0; i < str2.length(); i++) {for (int x = 0, y = str2.length() - i - x; y <= str2.length(); x++, y++) {String substring = str2.substring(x, y);if (str1.contains(substring)) {return substring;}}}return null;
}
五、StringBuffer和StringBuilder
- 因为String对象是不可变对象,虽然可以共享常量对象,但是对于频繁字符串的修改和拼接操作,效率极低,空间消耗也比较高
- 因此,JDK又在java.lang包提供了可变字符序列StringBuffer和StringBuilder类型
1、StringBuffer与StringBuilder的理解
- java.lang.StringBuffer代表
可变的字符序列
,JDK1.0中声明 - 可以对字符串内容进行增删,此时不会产生新的对象
//情况1:
String s = new String("我喜欢学习");
//情况2:
StringBuffer buffer = new StringBuffer("我喜欢学习");
buffer.append("数学");
- StringBuilder 和 StringBuffer 非常类似,均代表可变的字符序列,而且提供相关功能的方法也一样
- 区分String、StringBuffer、StringBuilder
- String:不可变的字符序列; 底层使用char[]数组存储(JDK8.0中)
- StringBuffer:可变的字符序列;线程安全(方法有synchronized修饰),效率低;底层使用char[]数组存储 (JDK8.0中)
- StringBuilder:可变的字符序列; jdk1.5引入,线程不安全的,效率高;底层使用char[]数组存储(JDK8.0中)
2、StringBuilder、StringBuffer的API
StringBuilder、StringBuffer的API是完全一致的,并且很多方法与String相同
常用API
- StringBuffer append(xx):提供了很多的append()方法,用于进行字符串追加的方式拼接
- StringBuffer delete(int start, int end):删除[start,end)之间字符
- StringBuffer deleteCharAt(int index):删除[index]位置字符
- StringBuffer replace(int start, int end, String str):替换[start,end)范围的字符序列为str
- void setCharAt(int index, char c):替换[index]位置字符
- char charAt(int index):查找指定index位置上的字符
- StringBuffer insert(int index, xx):在[index]位置插入xx
- int length():返回存储的字符数据的长度
- StringBuffer reverse():反转
@Test
public void test1(){StringBuilder sBuilder = new StringBuilder();sBuilder.append("abc").append("123").append("def"); //方法链的调用System.out.println(sBuilder); StringBuilder sBuilder = new StringBuilder("hello");sBuilder.insert(2, "中");System.out.println(sBuilder); // he中lloStringBuilder sBuilder1 = sBuilder.reverse();System.out.println("反转字符串:" + sBuilder); // oll中ehSystem.out.println("反转返回字符串:" + sBuilder1); // oll中ehSystem.out.println("反转字符串是否与返回字符串是同一个对象:" + (sBuilder == sBuilder1)); // trueSystem.out.println("字符串长度:" + sBuilder.length()); //实际存储的字符的个数 // 6
}
其它API
- 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的最后一次出现下标
- String substring(int start):截取当前字符序列[start,最后]
- String substring(int start, int end):截取当前字符序列[start,end)
- String toString():返回此序列中数据的字符串表示形式
- void setLength(int newLength) :设置当前字符序列长度为newLength
3、效率测试
测试String、StringBuffer、StringBuilder在操作数据方面的效率
@Test
public void test4() {//初始设置long startTime = 0L;long endTime = 0L;String text = "";StringBuffer buffer = new StringBuffer("");StringBuilder builder = new StringBuilder("");//开始对比startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {buffer.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuffer的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {builder.append(String.valueOf(i));}endTime = System.currentTimeMillis();System.out.println("StringBuilder的执行时间:" + (endTime - startTime));startTime = System.currentTimeMillis();for (int i = 0; i < 20000; i++) {text = text + i;}endTime = System.currentTimeMillis();System.out.println("String的执行时间:" + (endTime - startTime));
}
输出结果:
StringBuffer的执行时间:14
StringBuilder的执行时间:2
String的执行时间:264