javaSE基础-字符串
字符串
String类
定义:使用一对“”(引号)引起来表示
public final class String implements java.io.Serializable,
Comparable<String>, CharSequence {
private final char value[];
}
//String声明为final的,不可被继承
//String实现了Serializable接口:表示字符串是支持序列化的
实现了Comparable接口:表示String可以比较大小
//String内部定义了 final char[] value用于存储字符串数据(jdk8,之后新的版本为:byte[] value)
特点
String:代表不可变的字符串序列,即不可变特性
- 字符串重新赋值时,需要重写指定内存区域赋值,不能使用原有的value进行赋值
- 当对现有的字符串进行连接操作时,也需要重新指定区域赋值,不能使用原有的value
- 当调用String的replace()方法修改指定字符串或字符时,需要重新指定内存区域,不能使用原有的value
说明
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
字符串常量池中是不会存储相同内容(相同内容是指使用String类重写equals()比较,返回true)的字符串
常用创建字符串的方式
方式一:通过字面量定义的方式
//通过字面量定义的方式:此时的s1和s2的数据声明在 方法区中的字符串常量池中
tring s1 = "abc";
方式二:通过new + 构造器的方式
//通过new + 构造器的方式:此时s3和s4保存的地址值,是数据在堆空间中开辟空间以后对应字符串常量池的数据
String s3 = new String("abc");
Stirng创建方式内存示意图
注意:new方式创建对象,在内存中创建了几个对象?如:String s = new String("abc");
两个对象:一个是堆空间中new结构,另一个是char[]对应的常量池中的数据:“abc“
示例一
@Test
public void test1(){
//通过字面量定义的方式
String s1 = "abc";
String s2 = "abc";
//通过new + 构造器的方式
String s3 = new String("abc");
String s4 = new String("abc");
System.out.println(s1 == s2);//true
System.out.println(s3 == s4);//false
System.out.println(s1 == s3);//false
System.out.println(s2 == s4);//false
System.out.println("*****************");
Person p1 = new Person("Tom", 19);
Person p2 = new Person("Tom", 19);
System.out.println(p1.name.equals(p2.name));//true
System.out.println(p1.name == p2.name);//true
p1.name="Mary";
System.out.println(p2.name);//Tom
}
示例二
/**
* 结论:
* 1、常量与常量的拼接结果在常量池,且常量池中不会存在相同内容的常量
* 2、只要其中一个变量,结果就在堆中
* 3、如果拼接的结果调用intern()方法,返回值就在常量池中
*/
@Test
public void test2(){
String s1 = "javaSE";
String s2 = "SpringBoot";
String s3 = "javaSESpringBoot";
String s4 = "javaSE" + "SpringBoot";
String s5 = s1 + "SpringBoot";
String s6 = "javaSE" + s2;
String s7 = s1 + s2;
System.out.println(s3 == s4);//true
System.out.println(s3 == s5);//false
System.out.println(s3 == s6);//false
System.out.println(s3 == s7);//false
System.out.println(s6 == s7);//false
String s8 = s5.intern();//返回值s8使用的是常量池中的javaSESpringBoot
System.out.println(s3 == s8);//true
String s9 = "javaEEHello";
String s10 = "javaEE";
String s11 = s10 + "Hello";
System.out.println(s9 == s11); //false
String s12 = "javaEEHello";
final String s13 = "javaEE";
String s14 = s13 + "Hello"; //常量 + 常量 数据存储在常量池中
System.out.println(s12 == s14);//true
}
案例:常量池中的字符串不可变性
public class StringTest2 {
String str = new String("hello");
char[] ch = {'t', 'e', 's', 't'};
//对str 和 ch 重新赋值操作
void change(String str, char[] ch){
str = "hello word";
ch[0] = 'b';
}
public static void main(String[] args) {
StringTest2 s = new StringTest2();
s.change(s.str, s.ch);
System.out.println(s.str);//hello --> String存储在常量池中是不可变的
System.out.println(s.ch);//'best'
}
}
String常用方法
常用方法1
int length():返回字符串的长度
char charAt(int index):返回某索引处的字符
boolean isEmpty():判断是否是空字符串
String toLowerCase():使用默认语言环境,将String中的所有字符转换为小写
String toUpperCase():使用默认语言环境,将String中的所有字符转换为大写
String trim():返回字符串的副本,忽略前部空白和尾部空白
boolean equals(Object obj):比较字符串的内容是否相同
boolean equalsIgnoreCase(String anotherString):与equals方法类似,忽略大小写
String concat(String str):指定字符串连接到此字符串的结尾,等价于“+”
int compareTo(String anotherString):比较两个字符串的大小
String substring(int beginIndex):返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个字符串
String substring(int beginIndex, int endIndex):返回一个新的字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串
示例一
@Test
public void test1() {
String s1 = "HelloWorld";
char c = s1.charAt(2);
System.out.println(c);// l
String s2 = "";
System.out.println(s2.isEmpty()); //true
String s3 = " hel le,wor ld ";
System.out.println("----" + s3 + "----");//---- hel le,wor ld ----
String s4 = s3.trim();
System.out.println("----" + s4 + "----");//----hel le,wor ld----
String s5 = "helloworld";
System.out.println(s5.equalsIgnoreCase(s1));//true
String s6 = s5.concat("你好");
System.out.println(s6);//helloworld你好
String s7 = "abc";
int a = s7.compareTo("abd");
System.out.println(a);//-1
String s = s7.substring(2);
System.out.println(s);//c
String ss = s1.substring(2, 4);
System.out.println(ss);//ll
}
常用方法2
boolean endWith(String suffix):测试此字符串是否以指定的后缀结束
boolean startWith(String prefix):测试此字符串是否以指定的前缀结束
boolean startWith(String prefix, int toffset):测试此字符串从指定索引开始的子字符串是否以指定的字符开始boolean contains(CharSequence s):当且仅当此字符串包含指定的char值序列时,返回true
int indexOf(String str):返回指定字符串在此字符中第一次出现处的索引
int indexOf(String str, int fromIndex):返回指定字符串在此字符中第一次出现处的索引,指定开始索引的位置
int lastIndexOf(String str):返回指定子符串在此字符串最右出现处的索引,索引值还是从左边开始计数
int lastIndexOf(String str, int fromIndex):返回指定字符串在此字符串中最后一次出现处,从指定的索引开始反向索引
注:indexOf和lastIndexOf如果没有找到会返回-1
示例二
@Test
public void test2() {
String str1 = "helloworld";
boolean b1 = str1.endsWith("rld");
System.out.println(b1);//true
boolean b2 = str1.startsWith("he");
System.out.println(b2);//true
boolean b3 = str1.startsWith("ll", 2);
System.out.println(b3);//true
String str2 = "wor";
System.out.println(str1.contains(str2));//true
System.out.println(str1.indexOf("lol"));//-1 没有找到
System.out.println(str1.indexOf("lo", 5));//-1 没有找到
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or"));// 7
System.out.println(str3.lastIndexOf("or", 6));//4
}
常用方法3
替换:
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 替换此字符串匹配给定的正则表达式的第一个子字符串
匹配:
boolean matches(String regex):告知此字符串是否匹配给定的正则表达式
切片:
String[] split(String regex):根据给定正则表达式的匹配拆分此字符串
String[] split(String regex, int limit):根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部放到最后一个元素中
示例三
@Test
public void test3(){
String str1 = "你好,北京欢迎您!";
String str2 = str1.replace('您', '你');
System.out.println(str2);
System.out.println(str1);
String str3 = str1.replace("您", "大家");
System.out.println(str3);
System.out.println("*************************");
String str = "12hello34world5java7891mysql1456";
//把字符串中的数字替换成,如果结果中开头和结尾有,的话去掉
String s = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(s);
String str4 = "12345";
//判断str4 字符串中是否全部有数字组成,即有1-n个数字组成
boolean b1 = str4.matches("\\d+");
System.out.println(b1);
String tel = "0518-1234398";
//判断这是否是一个固定电话
boolean b2 = tel.matches("0518-\\d{7,8}");
System.out.println(b2);
System.out.println("******************");
String str5 = "hello|world|java";
String[] strs = str5.split("\\|");
for (int i = 0; i < strs.length; i++) {
System.out.println(strs[i]);
}
}
String类与其它结构之间的转换
String 与 byte[]转换
/**
* 编码:String --> byte[]:调用String的getBytes()
* 解码:byte[] --> String:调用String的构造器
*
* 说明:解码与编码过程使用的字符集要一致
*/
@Test
public void test3() throws UnsupportedEncodingException {
String str1 = "abc123北京";
byte[] bytes = str1.getBytes(); //默认使用系统的编码集
System.out.println(Arrays.toString(bytes));
byte[] bytes1 = str1.getBytes("gbk"); //使用指定的编码集
System.out.println(Arrays.toString(bytes1));
System.out.println("*********解码***********");
String str2 = new String(bytes1);
System.out.println(str2); //出现解码乱码
String gbk = new String(bytes1, "gbk");
System.out.println(gbk);
}
String 与 char[] 转换
/**
* String --> char[] 之间的转换: 调用String的toCharArray()
* char[] --> String: 调用String的构造器
*/
@Test
public void test2(){
String str1 = "abc124";
char[] ch = str1.toCharArray();
for (int i = 0; i < ch.length; i++) {
System.out.println(ch[i]);
}
char[] arr = new char[]{'1','2','a','b'};
String str2 = new String(arr);
System.out.println(str2);
}
String 与 基本数据类型、包装类转换
/**
* String --> 基本数据类型、包装类,调用包装类的静态方法:parseXxx()
* 基本数据类型、包装类 --> String: 调用String重载的valueOf(xxx)
*/
@Test
public void test1(){
String str1 = "123";
int num = Integer.parseInt(str1);
System.out.println(num);
String str2 = String.valueOf(num);
System.out.println(str2);
}
String 与 StringBuffer / StringBuilder 转换
/**
* String --> StringBuffer\StringBuilder:调用StringBuffer、StringBuilder构造器
* StringBuffer\StringBuilder --> String: ①调用String的构造器 ②xxx.toString()
*/
public StringBuffer(String str) {}
public StringBuilder(String str) {}
public String(StringBuffer buffer) {}
public String(StringBuilder builder) {}
StringBuffer 与 StringBuilder
常用方法:
StringBuffer append(xxx):提供了很多的append()的方法,用于进行字符串拼接
StringBuffer delete(int start, int end):删除指定位置的内容
StringBuffer replace(int start, int end, String str):把[start, end)的位置替换为str
StringBuffer insert(int offset, xxx):在指定位置插入xxx
StringBuffer reverse():把当前字符串序列逆转
public int indexOf(String str):查找指定字符串的索引
public String substring(int start, int end): 返回一个从start开始到end索引结束的左闭右开区间的子字符串
public int length():返回字符串长度
public char charAt(int n):返回一个指定位置上的字符
public void setCharAt(int n,char ch):在指定位置上替换一个字符
示例
@Test
public void test2(){
StringBuffer s1 = new StringBuffer("abc");
s1.append(1);
s1.append('1');
//s1.replace(1, 3, "hello"); //ahello11
//s1.insert(2,"java"); //abjavac11
//s1.reverse();//11cba
//s1.delete(1, 3);//a11
//char c = s1.charAt(2);
//System.out.println(c);//c
int index = s1.indexOf("bc");
System.out.println(index);//1
String substring = s1.substring(1, 3);
System.out.println(substring);//bc
s1.setCharAt(2, '你');//ab你11
System.out.println(s1);
System.out.println(s1.length());
}
注意: append()方法可以添加null,但StringBuilder / StringBuffer 构造器不能添加null对象
@Test
public void test1(){
String str = null;
StringBuffer sb = new StringBuffer();
sb.append(str);
System.out.println(sb.length());//4
System.out.println(sb);//null "null"
StringBuffer sb1 = new StringBuffer(str); //NullPointerException
System.out.println(sb1);
}
其它拓展
1、String / StringBuffer / StringBuilder 的三者异同
相同:三者底层都是char[] 存储数据(jdk8及以下)
不同:
String:不可变的字符序列,
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字节的字符数组, sb1.length()=0
sb1.append('a'); //value[0] = 'a';
sb1.append('b'); //value[1] = 'b';
StringBuffer sb2 = new StringBuffer("abc"); // char[] value = new char["abc".length() + 16];
//问题1:System.out.println(sb2.length()); //3
//问题2:扩容问题:如果要添加的数据底层数组盛不下了,那就需要扩容底层的数组。
默认情况下,扩容为原来容量的2倍+2,同时将原有数组中的元素复制到新的数组中。
说明:开发中使用:StringBuffer(int capacity)或 StringBuilder(int capacity)
2、将一个字符串中部分的字符进行反转
案例一:比如 "abcdefg" --> "abfedcg"
click me
public class StringExercise {
//方式一:先将字符串转换为char[],在反转指定位置上的字符,再将char[]转换为字符串
static String reverse(String str, int startIndex, int endIndex){
if(str != null && str != ""){
char[] chars = str.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;
}
//方式二:将字符串使用substring()拼接,反转字符部分使用charAt()索引到字符进行拼接
static String reverse1(String str, int startIndex, int endIndex){
if(str != null && str != ""){
String subStr = str.substring(0, startIndex);
for (int i = endIndex; startIndex <= i ; i--) {
subStr += str.charAt(i);
}
subStr += str.substring(endIndex + 1);
return subStr;
}
return null;
}
//方式三:在方式二的基础上优化字符串拼接,使用StringBuilder更高效的方式拼接反转的字符操作
static String reverse2(String str, int startIndex, int endIndex){
if(str != null && str != ""){
StringBuilder sb = new StringBuilder(str.length());
String substring = str.substring(0, startIndex);
sb.append(substring);
for (int i = endIndex; i >= startIndex ; i--) {
sb.append(str.charAt(i));
}
sb.append(str.substring(endIndex + 1));
return new String(sb);
}
return null;
}
public static void main(String[] args) {
String str = "abcdefg";
String reverseStr = reverse1(str, 2, 5);
System.out.println(reverseStr);
}
}
3、获取一个字符串在另一个字符串中出现的次数
案例二:比如 获取“ab” 在 “abkkcadkabkbfkaabskabge”中的次数
click me
public class StringExercise2 {
public static int getCount(String mainStr, String subStr){
int subLength = subStr.length();
if(mainStr.length() > subLength){
int count = 0;
int index = 0;
//方式一:查找到subStr之后,截取mainStr后面字符串作为新的mainStr
//while((index = mainStr.indexOf(subStr)) != -1){
// count ++;
// mainStr = mainStr.substring(index + subLength);
//}
//方式二:
while ((index = mainStr.indexOf(subStr, index)) != -1){
count++;
index += subLength;
}
return count;
}else {
return 0;
}
}
public static void main(String[] args) {
String subStr = "ab";
String mainStr = "abkkcadkabkbfkaabskabge";
int count = getCount(mainStr, subStr);
System.out.println(count);
}
}
4、获取两个字符串中最大相同字串
案例三:比如 str1 = "abcwerthehelloyuiodef" str2 = "cvhellobnm"
click me
public class StringExercise3 {
//情况一:只有一个最大相同字串
public String getMaxSameString(String str1, String str2){
if(str1 != null && str2 != null){
String maxStr = (str1.length() >= str2.length())?str1:str2;
String minStr = (str1.length() < str2.length())?str1:str2;
int length = minStr.length();
for (int i = 0; i < length; i++) {
for(int x=0,y = length-i;y<=length;x++,y++){
String subStr = minStr.substring(x,y);
if(maxStr.contains(subStr)){
return subStr;
}
}
}
}
return null;
}
//情况二:多个最长字串
public String[] getMaxSameString1(String str1, String str2){
if(str1 != null && str2 != null){
StringBuffer sBuffer = new StringBuffer();
String maxString = (str1.length() >= str2.length())?str1:str2;
String minString = (str1.length() < str2.length())?str1:str2;
int len = minString.length();
for (int i = 0; i < len; i++) {
for(int x=0,y=len-i;y<= len; x++,y++){
String subStr = minString.substring(x,y);
if(maxString.contains(subStr)){
sBuffer.append(subStr + ",");
}
}
if(sBuffer.length() != 0){
break;
}
}
String[] split = sBuffer.toString().replaceAll("\\,$", "").split("\\,");
return split;
}
return null;
}
@Test
public void test1(){
String str1 = "abcwerthehelloyuiodef";
String str2 = "cvhellobnmiodef";
String[] maxSameString = getMaxSameString1(str1, str2);
System.out.println(Arrays.toString(maxSameString));
}
}