文章目录
- 1.String类的特性与使用
- 1.1 String类的特性
- 1.2 String对象的创建方式
- 1.3 String 的使用(不同的拼接操作)
- 2.String常用方法
- 2.1 String的常用方法一
- 2.2 String常用方法二
- 2.3 String常用方法三
1.String类的特性与使用
1.1 String类的特性
String 代表字符串。Java 程序中的所有字符串字面值(如 “abc” )都作为此类的实例实现。
特性:
1.String是声明为final的,不可被继承。
2.String实现了Serializable接口:表示字符串是支持序列化的。
实现了Comparable接口:表示String可以比较大小。
3.String内部定义了final char[] value用于存储字符串数据。
4.String:代表不可变的字符序列。简称:不可变性。
这里的不可变说的是存储在常量池中的字符串常量(字符数组 char value[])的值是不可变的, 而不是String类型的变量的值是不可变的。)
体现:①当对字符串重新赋值时,需要重新指定区域赋值,不能使用原有的value进行赋值。
String s1 = "abc"; //字面量的定义方式
String s2 = "abc";
s1 = "hello";System.out.println(s1 == s2); //比较s1和s2的地址值
System.out.println(s1);
System.out.println(s2);
测试结果如下:
②当对现有的字符串进行连接操作时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
String s2 = "abc";
String s3 = "abc";
s3 += "def";System.out.println(s3); //abcdef
System.out.println(s2); //abc
System.out.println(s2 == s3); //false
测试结果如下:
③当调用String的replace()方法修改指定字符或字符串时,也需要重新指定内存区域赋值,不能使用原有的value进行赋值。
String s4 = "abc";
String s5 = s4.replace('a', 'z');System.out.println(s4);
System.out.println(s5);
System.out.println(s4 == s5);
测试结果如下:
5.通过"字面量"的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中。
6.字符串常量池中是不会存储相同内容的字符串的。
1.2 String对象的创建方式
- 通过字面量定义的方式
此时定义的数据声明在方法区中的字符串常量池中。
2.通过new + 构造器的方式
此时创建的String对象保存的地址值,是数据在堆空间中开辟空间以后对应的地址值。
@Test
public void test2(){//通过字面量定义的方式://此时的s1和s2的数据javaEE声明在方法区中的字符串常量池中。String s1 = "javaEE";String s2 = "javaEE";//通过new + 构造器的方式:此时的s3和s4保存的地址值,//是数据在堆空间中开辟空间以后对应的地址值。String s3 = new String("javaEE");String s4 = new String("javaEE");System.out.println(s1 == s2);//trueSystem.out.println(s1 == s3);//falseSystem.out.println(s1 == s4);//falseSystem.out.println(s3 == s4);//false}
测试结果如下:
下面通过这样一段代码来加深一下对String对象创建方式的理解:
Person p1 = new Person("Tom", 12);
Person p2 = new Person("Tom", 12);System.out.println(p1.name.equals(p2.name)); //true
System.out.println(p1.name == p2.name); //truep1.name = "Jerry";
System.out.println(p2.name); //Tom
思考上述代码段的运行结果是怎么样子的呢?
首先第一个输出是true,因为String类重写了Object类的equals方法,比较的是String对象的值,所以只要字符串的值相同,结果就为true。
第二个也为true,这是因为在用构造器传参的过程中,其实是以字面量的方式声明的p1.name和p2.name,所以p1.name和p2.name是存储在方法区中的字符串常量池中的,且是同一份。只不过p1和p2这两个Person类的对象是声明在了堆中的不同地方而已,p1和p2两对象的name属性值的地址是一样的,都指向方法区的字符串常量池的同 一片地址空间。 内存结构如下图所示:
所以这个时候如果试图改变p1的name值(以字面量的方式),那么就是在常量池中另外开辟了一片空间,p2的name值不会受到影响,还是“Tom”。
1.3 String 的使用(不同的拼接操作)
思考下述关于String对象连接操作的代码段的运行结果。
public void test3(){String s1 = "javaEE";String s2 = "hadoop";String s3 = "javaEEhadoop";String s4 = "javaEE" + "hadoop";String s5 = s1 + "hadoop";String s6 = "javaEE" + s2;String s7 = s1 + s2;System.out.println(s3 == s4);//trueSystem.out.println(s3 == s5);//falseSystem.out.println(s3 == s6);//falseSystem.out.println(s3 == s7);//falseSystem.out.println(s5 == s6);//falseSystem.out.println(s5 == s7);//falseSystem.out.println(s6 == s7);//false
}
下面给出运行结果:
为什么会这样呢?这是因为String对象的连接操作有下述三条结论:
1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。
2.只要其中有一个是变量,结果就在堆中。
3.如果拼接的结果调用intern()方法,返回值就在常量池中。
由结论1和2,不难验证出上述代码段的运行结果。下面给出内存结构图辅助理解:
其中,intern()方法是String类的一个方法,其返回值的内容声明在常量池中。
2.String常用方法
2.1 String的常用方法一
- **int length():**返回字符串的长度: return value.length
String s1 = "HelloWorld";System.out.println(s1.length());
测试结果如下:
- char charAt(int index): 返回某索引处的字符return value[index]
System.out.println(s1.charAt(0));
System.out.println(s1.charAt(9));
System.out.println(s1.charAt(10));
测试结果如下:
可见,若索引值超过String下标时,会报下标越界的错误。
- **boolean isEmpty():**判断是否是空字符串:return value.length == 0
String s1 = "HelloWorld";
String s2 = "";
System.out.println(s1.isEmpty());
System.out.println(s2.isEmpty());
测试结果如下:
- **String toLowerCase():**使用默认语言环境,将 String 中的所有字符转换为小写
String s1 = "HelloWorld";
String s2 = s1.toLowerCase();
System.out.println(s1); //s1不可变的,仍然为原来的字符串
System.out.println(s2); //改成小写以后的字符串
测试结果如下:
- **String toUpperCase():**使用默认语言环境,将 String 中的所有字符转换为大写
String s1 = "HelloWorld";
String s2 = s1.toUpperCase();
System.out.println(s1); //s1不可变的,仍然为原来的字符串
System.out.println(s2); //改成大写以后的字符串
测试结果如下:
- **String trim():**返回字符串的副本,忽略前导空白和尾部空白
String s3 = " he llo world ";
String s4 = s3.trim();
System.out.println("-----" + s3 + "-----");
System.out.println("-----" + s4 + "-----");
测试结果如下:
- **boolean equals(Object obj):**比较字符串的内容是否相同
- **boolean equalsIgnoreCase(String anotherString):**与equals方法类似,忽略大小写
String s1 = "HelloWorld";
String s2 = "helloworld";
System.out.println(s1.equals(s2));
System.out.println(s1.equalsIgnoreCase(s2));
测试结果如下:
- **String concat(String str):**将指定字符串连接到此字符串的结尾。 等价于用“+”
String s3 = "abc";
String s4 = s3.concat("def");
System.out.println(s4);
测试结果如下:
- **int compareTo(String anotherString):**比较两个字符串的大小
String s5 = "abc";
String s6 = new String("abe"); //这个时候和字符串是怎样赋的值已经没有关系了,因为比较的是内容
System.out.println(s5.compareTo(s6));//涉及到字符串排序
测试结果如下:
- **String substring(int beginIndex):**返回一个新的字符串,它是此字符串的从beginIndex开始截取到最后的一个子字符串。(即从指定索引位置到结尾)
String s7 = "北京尚硅谷教育";
String s8 = s7.substring(2)
System.out.println(s7);
System.out.println(s8);
测试结果如下:
- String substring(int beginIndex, int endIndex) :返回一个新字符串,它是此字符串从beginIndex开始截取到endIndex(不包含)的一个子字符串。(左闭右开)
String s7 = "北京尚硅谷教育";
String s9 = s7.substring(2, 5);
System.out.println(s7);
System.out.println(s9);
测试结果如下:
2.2 String常用方法二
- **boolean endsWith(String suffix):**测试此字符串是否以指定的后缀结束
String str1 = "hellowworld";
boolean b1 = str1.endsWith("rld"); //形参处可以是单个的字符,也可以是字符串
System.out.println(b1);
测试结果如下:
- **boolean startsWith(String prefix):**测试此字符串是否以指定的前缀开始
String str1 = "hellowworld";
boolean b2 = str1.startsWith("He"); //形参处可以是单个的字符,也可以是字符串
boolean b3 = str1.startsWith("he"); //形参处可以是单个的字符,也可以是字符串
System.out.println(b2);
System.out.println(b3);
测试结果如下:
- **boolean startsWith(String prefix, int toffset):**测试此字符串从指定索引开始的子字符串是否以指定前缀开始
String str1 = "hellowworld";
boolean b3 = str1.startsWith("ll",2); //从str1的指定toffset处开始的字符串是否以prefix开始
System.out.println(b3);
测试结果如下:
- **boolean contains(CharSequence s):**当且仅当此字符串包含指定的 char 值序列时,返回 true
String s1 = "helloworld";
String s2 = "wor";
System.out.println(s1.contains(s2));
测试结果如下:
- **int indexOf(String str):**返回指定子字符串在此字符串中第一次出现处的索引
- **int indexOf(String str, int fromIndex):**返回指定子字符串在此字符串中第一次出现处的索引,从指定的索引开始
String str1 = "helloworld";
System.out.println(str1.indexOf("lo"));
System.out.println(str1.indexOf("lol"));
System.out.println(str1.indexOf("lo", 5));
测试结果如下:
- **int lastIndexOf(String str):**返回指定子字符串在此字符串中最右边出现处的索引
- **int lastIndexOf(String str, int fromIndex):**返回指定子字符串在此字符串中最后一次出现处的索引,从指定的索引开始反向搜索
String str3 = "hellorworld";
System.out.println(str3.lastIndexOf("or"));
System.out.println(str3.lastIndexOf("or", 6));
测试结果如下:
2.3 String常用方法三
- **String replace(char oldChar, char newChar):**返回一个新的字符串,它是通过用 newChar 替换此字符串中出现的所有 oldChar 得到的。
String str1 = "北京尚硅谷教育北京";
String str2 = str1.replace('北', '东');
System.out.println(str1);
System.out.println(str2);
测试结果如下:
- **String replace(CharSequence target, CharSequence replacement):**使用指定的字面值替换序列替换此字符串所有匹配字面值目标序列的子字符串。
String str1 = "北京尚硅谷教育北京";
String str3 = str1.replace("北京", "上海");
System.out.println(str3);
测试结果如下:
- **String replaceAll(String regex, String replacement):**使用给定的 replacement 替换此字符串所有匹配给定的正则表达式的子字符串。(regex:全称为:regular expression(正则表达式))
String str = "12hello34world5java7891mysql456";
//把字符串中的数字替换成',',如果结果中开头和结尾有','的话去掉
String string = str.replaceAll("\\d+", ",").replaceAll("^,|,$", "");
System.out.println(string);
测试结果如下:
- **String replaceFirst(String regex, String replacement):**使用给定的 replacement 替换此字符串匹配给定的正则表达式的第一个子字符串。
- **boolean matches(String regex):**告知此字符串是否匹配给定的正则表达式。
String str = "12345";
//判断str字符串中是否全部有数字组成,即有1-n个数字组成
boolean matches = str.matches("\\d+");
System.out.println(matches);
String tel = "0571-4534289";
//判断这是否是一个杭州的固定电话
boolean result = tel.matches("0571-\\d{7,8}");
System.out.println(result);
测试结果如下:
- **String[] split(String regex):**根据给定正则表达式的匹配拆分此字符串。
- **String[] split(String regex, int limit):**根据匹配给定的正则表达式来拆分此字符串,最多不超过limit个,如果超过了,剩下的全部都放到最后一个元素中。
String str = "hello|world|java";
String[] strs = str.split("\\|");
for (int i = 0; i < strs.length; i++) {System.out.println(strs[i]);
}
System.out.println("***********************");
str2 = "hello.world.java";
String[] strs2 = str2.split("\\.");
for (int i = 0; i < strs2.length; i++) {System.out.println(strs2[i]);
}
测试结果如下: