String类的概述
String的特性:不可变性
String类:代表字符串。Java程序中的所有字符串字面量(如"abc")都作为此类的实例实现。
String是一个final类,代表不可变得字符序列。该类不能被继承。
字符串是常量,用双引号引起来表示。它们的值在创建之后不能更改。
String对象的字符内容是存储在一个字符数组value[]的(jdk1.8及之前)。
1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原来的value进行赋值。
public class StringTest {
/**
* String:字符串,使用一对""引起来表示。
* 1.String声明为final的,不可被继承。
* 2.String实现了Serializable接口:表示字符串是支持序列化的。
* 实现了Comparable接口:表示String可以比较大小。
* 3.String内部定义了final char[] value用于存储字符串数据的。
* 4.String代表不可变的字符序列。简称不可变性。
* 体现:1.当对字符串重新赋值时,需要重写指定内存区域赋值,不能使用原来的value进行赋值。
* 2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
* 3.当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域,不能使用原有的value进行赋值。
* 5.通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
* 6.字符串常量池中是不会存储相同内容的字符串的。
*/
public static void main(String[] args) {
String s = "abc";
String n = "abc";
s = "ab";
System.out.println(s.toString());
System.out.println(n.toString());
}
}
2.当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
3.当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域,不能使用原有的value进行赋值。
源码如下:
String的实例化方式:两种
方式一:通过字面量的方式
方式二:通过new + 构造器的方式。
面试题:String s = new String("abc");通过前面这种创建对象,在内存中创建了几个对象?
两个:一个是在堆空间中new的结构,另一个是char[]对应的常量池中的数据:"abc"。
String不同拼接操作的对比
@Test
public void test1 (){
String s1 = "javaee";
String s2 = "aa";
String s3 = s1 + "aa";
String s4 = "javaee" + "aa";
String s5 = s1 + s2;
String s6 = s5.intern();
System.out.println(s3==s4);//false
System.out.println(s3==s5);//false
System.out.println(s3==s6);//false
System.out.println(s4==s5);//fasle
System.out.println(s4==s6);//true
System.out.println(s5==s6);//false
}
总结:
常量与常量拼接结果在常量池。且常量池中不会存在相同内容的常量。
只要其中有一个是变量,结果就在堆中。
如果拼接的结果调用类中的intern()方法,返回值就在常量池中。
String的常用方法1:
@Test
public void test1() {
String a = "HelloWorld";
//1.public int length():返回此字符串的长度。
System.out.println(a.length());//5
//2.char charAt(int index) :此字符串的指定索引处的 char 值。第一个字符值位于索引 0 处。
// System.out.println(a.charAt(5));//java.lang.StringIndexOutOfBoundsException: String index out of range: 5
char c = a.charAt(3);
System.out.println(c);//l
//3.public boolean isEmpty():判断字符串是否为空,是返回true
boolean isEmpty = a.isEmpty();
System.out.println(isEmpty);//false
//4.public String toLowerCase():使用默认区域设置的规则将此字符串中的所有字符转换为小写。
//调用该方法后返回的是一个新的字符串,原来的变量没有改变。相当于创建一个新对象并赋值。
String s = a.toLowerCase();
System.out.println(s);//helloworld
System.out.println(a);//HelloWorld
//5.public String toUpperCase():使用默认区域设置的规则将此字符串中的所有字符转换为大写。
String s1 = a.toUpperCase();
System.out.println(s1);//HELLOWORLD
System.out.println(a);//HelloWorld
//6.public String trim():返回一个字符串,其值为此字符串删除任何前导空格和尾随空格的值。
String b = " * * * ";
String trim = b.trim();
System.out.println(b);
System.out.println(trim);
//7. public boolean equals(Object anObject):比较字符串内容是否一样。
boolean b1 = b.equals(trim);
System.out.println(b1);//false
}
//8.public boolean equalsIgnoreCase(String anotherString):比较字符串内容是否一样,忽略大小写
boolean b2 = a.equalsIgnoreCase(s);
System.out.println(b2);//true
//9.public String concat(String str):将指定的字符串连接到此字符串的末尾。等价于用 +
/*Examples:
"cares".concat("s") returns "caress"
"to".concat("get").concat("her") returns "together"
*/
String hahaha = a.concat("hahaha");
System.out.println(hahaha);//HelloWorldhahaha.
//10.public int compareTo(String anotherString):
// 比较字符串大小,返回字符串长度之差。字符串长度不一样时,比较长度。字符串长度一样时,比较大小。
//a.compareTo(b):如果返回值等于0,则字符串一样。大于0,a的字符串长或大,小于0,b的字符串长或大。
String abc = "人人";
String abcd = "商场";
int i = abc.compareTo(abcd);
System.out.println(i);//-1676
//11.public String substring(int beginIndex):
// 返回该字符串的子字符串。子字符串以指定索引处的字符开始,并扩展到该字符串的末尾。索引从0开始
String ha = "发哈李芳芳很费劲";
String substring = ha.substring(5);
System.out.println(substring);//很费劲
//12.public String substring(int beginIndex, int endIndex):[)截取的是前闭后开区间
//"hamburger".substring(4, 8) returns "urge"
// "smiles".substring(1, 5) returns "mile"
System.out.println(ha.substring(5, 6));//很
String与基本数据类型、包装类之间的转换
String --->基本数据类型、包装类:调用包装类的静态方法:parseXxx(String str);
基本数据类型、包装类 --->String类型:调用String类中的静态方法:valueOf(基本数据类型 变量名)。
String与char[]数组之间的转换
String ---> char[]调用String中的toCharArray()
char[] --->String调用String的构造器
String与byte[]之间的转换
编码:String--->byte[]:调用String的getBytes()
解码:byte[]--->String:调用String的构造器
编码:字符串--->字节(看得懂--->看不懂的二进制数据)
解码:编码的逆过程,字节--->字符串(看不懂的二进制数据--->看得懂)
说明:解码时,要求解码使用的字符集
String,StringBuilder,StringBuffer三者的异同?
String:不可变的字符序列:底层都是使用char[]存储。
StringBuffer:可变的字符序列:线程安全的,效率低;底层使用char[]存储。构造一个字符串生成器,其中不包含字符,初始容量为 16 个字符。默认扩容机制是当前字符串容量左移一位然后加2。即(value.length << 1) + 2
StringBuilder:可变的字符序列:jdk5.0新增的,线程不安全的,效率高;底层使用char[]存储。构造一个字符串生成器,其中不包含字符,初始容量为 16 个字符。默认扩容机制是当前字符串容量左移一位然后加2。即(value.length << 1) + 2。
StringBuffer和StringBuilder的概述
源码分析:
String str = new String();//char[] value = new char[0];
String str1 = new String("abc");//char[] value = new char[]{'a','b','c'};
StringBuffer sb1 = new StringBuffer();//char [] value = new char[16];底层创建了一个长度是16的char[]。
char[] chars1 = new char[0];
System.out.println(chars1.length);//0
StringBuffer stringBuffer = new StringBuffer();
System.out.println(stringBuffer.length());//0
StringBuffer a1 = stringBuffer.append('a');
System.out.println(stringBuffer.length());//1
System.out.println(a1.length());//1
扩容问题:如果要添加的数据底层盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来的两倍+2,同时将原有数组中的元素复制到新的数组中。
StringBuffer的常用方法:
//StringBuffer的常用方法
StringBuffer stringBuffer = new StringBuffer();
// 1.public synchronized StringBuffer append(xxx):提供了很多的append()方法,用于进行字符串拼接。
StringBuffer stringBuffer1 = stringBuffer.append("abcdefg");
System.out.println(stringBuffer);//abcdefg
System.out.println(stringBuffer1);//abcdefg
//2.public synchronized StringBuffer delete(int start, int end):删除从索引位置start开始到end-1结束的一个前闭后开区间。
// 返回值是去掉删除部分的拼接。
StringBuffer stringBuffer2 = stringBuffer.delete(1, 3);
System.out.println(stringBuffer);//adefg
System.out.println(stringBuffer1);//adefg
System.out.println(stringBuffer2);//adefg
System.out.println(stringBuffer == stringBuffer1);//true
System.out.println(stringBuffer1 == stringBuffer2);//true
//3.public synchronized StringBuffer replace(int start, int end, String str):把[start,end)之间的字符串替换为str,
// 然后再返回该值
StringBuffer stringBuffer3 = stringBuffer.replace(0, 3, "123");
System.out.println(stringBuffer);//123fg
System.out.println(stringBuffer3);//123fg
//4.public StringBuffer insert(int offset, xxx) :在指定索引处插入xxx,该处原来的数据向右移,然后返回。
StringBuffer stringBuffer4 = stringBuffer.insert(2, 999);
System.out.println(stringBuffer);//129993fg
System.out.println(stringBuffer4);//129993fg
//5. public synchronized StringBuffer reverse():把当前字符序列反转
StringBuffer stringBuffer5 = stringBuffer.reverse();
System.out.println(stringBuffer);//gf399921
System.out.println(stringBuffer5);//gf399921
//6. public int indexOf(String str):在A字符串中搜索str字符串第一次出现的索引位置并返回,从索引0处开始搜索。
int i = stringBuffer.indexOf("9");
System.out.println(i);//3
//7.public synchronized String substring(int start, int end):在[start,end)区间返回一个新的子字符串
String substring = stringBuffer.substring(4,7);
System.out.println(stringBuffer);//gf399921
System.out.println(substring);//992
//8.public synchronized char charAt(int index):返回该处索引的字符。
char charAt = stringBuffer.charAt(7);
System.out.println(charAt);//1
String,StringBuilder,StringBuffer三者的执行效率
效率从高到低排列:StringBuilder>StringBuffer>String。
常见面试题
将字符串进行反转
/**
*
* 将一个字符串进行反转。
* 将字符串中指定部分进行反转,比如"abcdefg"反转成"abedcfg"
* 方式三:使用StringBuilder()
*/
public String reverse2(String s, int startIndex, int endIndex){
if (s != null) {
//1.截取startIndex之前的部分
StringBuilder stringBuilder = new StringBuilder(s.length());
stringBuilder.append(s.substring(0, startIndex));
//2.对要截取的部分进行反转
String s1 = s.substring(startIndex, endIndex + 1);
StringBuilder reverse = new StringBuilder(s1).reverse();
stringBuilder.append(reverse);
//3.拼接剩下的
stringBuilder.append(s.substring(endIndex + 1));
//4.将stringBuilder转换为字符串
String s2 = stringBuilder.toString();
return s2;
}
return null;
}
/**
* 将一个字符串进行反转。
* 将字符串中指定部分进行反转,比如"abcdefg"反转成"abedcfg"
* 方式一:转换为char[]
*/
public String reverse(String s, int startIndex, int endIndex) {
//将字符串转换为新的字符数组.
if (s != null) {
char[] chars = s.toCharArray();
for (int i = startIndex, j = endIndex; i < j; i++, j--) {
char temp = chars[i];
chars[i] = chars[j];
chars[j] = temp;
}
return new String(chars);
}
return null;
}
/**
* 将一个字符串进行反转。
* 将字符串中指定部分进行反转,比如"abcdefg"反转成"abedcfg"
* 第二种方式:字符串拼接
*
* @param s 自定义的字符串
* @param startIndex 反转的开始索引位置
* @param endIndex 反转的结束索引位置
* @return 反转后的字符串
*/
public String reverse1(String s, int startIndex, int endIndex) {
//1.字符串切割
String s1 = s.substring(0, startIndex);
//2.将要反转的部分进行反转,然后通过字符串拼接
for (int i = endIndex; i >= startIndex; i--) {
s1 += s.charAt(i);
}
//3.字符串切割,然后再拼接
String s2 = s.substring(endIndex + 1);//从endIndex + 1处开始截取
s1 += s2;
return s1;
}
@Test
public void test1() {
String reverse = reverse2("abcdefg", 1, 5);
System.out.println(reverse);
}
获取一个子字符串在主字符串中出现的次数
/**
* 获取一个子字符串在主字符串中出现的总次数
* @param mainString 主字符串
* @param sonString 子字符串
* @return 出现的总次数
*/
public int getCount(String mainString, String sonString) {
//获取两个字符串的长度
int mainLength = mainString.length();
int sonLength = sonString.length();
//子串在主串中出现的次数
int count = 0;
//子串在主串中每次出现的索引位置
int index;
if (mainLength >= sonLength) {
//子串在主串中第一次出现的索引位置
index = mainString.indexOf(sonString);
while (index != -1) {
count++;
index = mainString.indexOf(sonString, index + sonLength);
}
return count;
} else {
return count;
}
}
获取两个字符串中最大相同子串
获取两个字符串中最大相同子串(前提:两个字符串中只有一个最大的相同子串)
/**
* 获取两个字符串中最大相同子串,比如:
* str1 = "abachelloworldshell";str2 = "stfjkdhellofgjhkllshellworld";
* 将短的那个字符串进行长度依次递减的子串与较长的字符串进行比较。
*
* @param str1 一个字符串
* @param str2 另一个字符串
* @return 最大相同子串
*/
//前提:两个字符串中只有一个最大的相同子串
public String getMaxSameString(String str1, String str2) {
if (str1 != null && str2 != null) {
String maxString = (str1.length() >= str2.length()) ? str1 : str2;
String minString = (str1.length() < str2.length()) ? str1 : str2;
int length = minString.length();
//比较轮数
for (int i = 0; i < length; i++) {
//每一轮比较的次数
for (int j = 0, k = length - i; k <= length; j++, k++) {
String substring = minString.substring(j, k);
if (maxString.contains(substring)) {
return substring;
}
}
}
}
return null;
}
获取两个字符串中最大相同子串
/**
* 方式一:
* 获取两个字符串中最大相同子串,比如:
* str1 = "abachelloworldshellworld";str2 = "stfjkdhellofgjhkllshellworld";
* 将短的那个字符串进行长度依次递减的子串与较长的字符串进行比较。
*
* @param str1 一个字符串
* @param str2 另一个字符串
* @return 最大相同子串
*/
public String[] getMaxSameString2(String str1, String str2) {
if (str1 != null && str2 != null) {
String maxString = (str1.length() >= str2.length()) ? str1 : str2;
String minString = (str1.length() < str2.length()) ? str1 : str2;
int length = minString.length();
StringBuffer stringBuffer = new StringBuffer();
//比较轮数
for (int i = 0; i < length; i++) {
//每一轮比较的次数
for (int j = 0, k = length - i; k <= length; j++, k++) {
String substring = minString.substring(j, k);
if (maxString.contains(substring)) {
stringBuffer.append(substring + ",");//拼接获取到的最大相同子串
}
}
}
//将stringBuffer中的","换成" "。
String[] split = stringBuffer.toString().replaceAll(",$", "").split("\\,");
int count=0;//最大相同子串的个数
if (split.length > 0 && split != null) {
for (int i = 0; i < split.length; i++) {
if (split[i].length() >= split[0].length()) {
count++;
}
}
//创建一个新的字符串数组装最大相同子串
String[] strings = new String[count];
for (int i = 0; i < count; i++) {
strings[i]=split[i];
}
return strings;
}
}
return null;
}
/**
* 方式二:
* 获取两个字符串中最大相同子串,比如:
* str1 = "abachelloworldshellworld";str2 = "stfjkdhellofgjhkllshellworld";
* 将短的那个字符串进行长度依次递减的子串与较长的字符串进行比较。
*
* @param str1 一个字符串
* @param str2 另一个字符串
* @return 最大相同子串
*/
public String[] getMaxSameString1(String str1, String str2) {
if (str1 != null && str2 != null) {
String maxString = (str1.length() >= str2.length()) ? str1 : str2;
String minString = (str1.length() < str2.length()) ? str1 : str2;
int length = minString.length();
StringBuffer stringBuffer = new StringBuffer();
//比较轮数
for (int i = 0; i < length; i++) {
//每一轮比较的次数
for (int j = 0, k = length - i; k <= length; j++, k++) {
String substring = minString.substring(j, k);
if (maxString.contains(substring)) {
stringBuffer.append(substring + ",");//拼接获取到的最大相同子串
}
}
if (stringBuffer.length() != 0) {//不理解??
break;
}
}
//将stringBuffer中的","换成" "。
String[] split = stringBuffer.toString().replaceAll(",$", "").split("\\,");
return split;
}
return null;
}