String类
目录
字符串常量
我们俗称的字符串常量,其实程序之中不会提供有字符串这样的“基本数据类型”,提供的只是一个String类,所以任何使用" "定义的字符串常量实际上描述的都是一个String类的匿名对象。
String类对象的直接赋值: 将一个匿名对象设置一个具体的引用,相当于开辟一个栈内存,指向这个匿名对象,这个匿名对象是存在堆内存的。
String类对象直接赋值 :String str = "Daxiong";
字符串常量 :"Daxiong"
可以发现:字符串常量可以调用equals()方法实现对象相等的判断,所以程序中没有字符串常量这种基本类型,有的只是String类的匿名对象。
//验证字符串常量是匿名类对象
public class Stringdemo {
public static void main(String[] args) {
String str = "Daxiong";
System.out.println("Daxiong".equals(str)); //true
//"Daxiong"能调用equals方法,说明这是个匿名类对象
}
}
常见的方法
charAt(int index):返回字符串指定位置字符
public class Demo{
public static void main(String[] args){
String s = "jixiaoqizhenshuai";
char what =s.charAt(5);
System.out.println(what);
}
}//应该输出a
indexOf(String s):返回指定字符串第一次出现的位置
public class Test {
public static void main(String[] args) {
String s = "findStrring"; //定义初始化一个字符串findString
// 从头开始查找是否存在指定的字符 //结果如下
System.out.println(s.indexOf("d")); // 结果是3
// 从第四个字符位置开始往后继续查找S,包含当前位置
System.out.println(s.indexOf("S", 3)); //结果是4
//若指定字符串中没有该字符则系统返回-1
System.out.println(s.indexOf("o")); //结果是-1
//从指定的索引处开始向后搜索,返回在此字符串中最后一次出现的指定子字符串的索引
System.out.println(s.lastIndexOf("r")); //结果是7
}
}
startWith(String s):测试字符串是否以指定前缀开始
public class Test {
public static void main(String args[]) {
String Str = new String("www.runoob.com");
System.out.print("返回值 :" );
System.out.println(Str.startsWith("www") );
System.out.print("返回值 :" );
System.out.println(Str.startsWith("runoob") );
System.out.print("返回值 :" );
System.out.println(Str.startsWith("runoob", 4) );
}
}//返回值 :true 返回值 :false 返回值 :true
endsWith(String s):测试字符串是否以指定的后缀开始
public class Test {
public static void main(String args[]) {
String Str = new String("菜鸟教程:www.runoob.com");
boolean retVal;
retVal = Str.endsWith( "runoob" );
System.out.println("返回值 = " + retVal );
retVal = Str.endsWith( "com" );
System.out.println("返回值 = " + retVal );
}
}//返回值 = false 返回值 = true
subString(int index):返回字符串的子字符串
replacpublic class RunoobTest {
public static void main(String args[]) {
String Str = new String("This is text");
System.out.print("返回值 :" );
System.out.println(Str.substring(4) );
System.out.print("返回值 :" );
System.out.println(Str.substring(4, 10) );
}
}e(char a,char b):替换字符串的指定字符//返回值:is text 返回值: is te
trim():去掉字符串的前后空格
public class Test {
public static void main(String args[]) {
String Str = new String(" www.runoob.com ");
System.out.print("原始值 :" );
System.out.println( Str );
System.out.print("删除头尾空白 :" );
System.out.println( Str.trim() );
}
}//原始值 : www.runoob.com 删除头尾空白 :www.runoob.com
concat(String str):连接两个字符串
public class Demo10String {
public static void main(String[] args) {
//拼接字符串相同点
String str1="Hello";
String str2="World";
String str3=str1.concat(str2);
String str4=str1+str2;
System.out.println(str3); //输出:HelloWorld
System.out.println(str4); //输出:HelloWorld
//不同点
String str="Hello" + 5; //输出:Hello5
System.out.println(str);
}
split(String regex):给定正则表达是的匹配来拆分字符串
String test0 = "meow#meow#wo#yao#chi#rou";
for (String a: test0.split("#")){
System.out.println(a);
}//输出:meow meow wo yao chi rou
正则表达式
字符通配符
在Java中,正则表达式是处理字符串的强大工具,它提供了多种字符通配符来匹配字符串中的模式。这些通配符包括:
.
(点号):匹配除换行符之外的任何单个字符。*
(星号):匹配前面的子表达式零次或多次。+
(加号):匹配前面的子表达式一次或多次。?
(问号):匹配前面的子表达式零次或一次。[xyz]
:字符集合。匹配所包含的任意一个字符。[^xyz]
:负值字符集合。匹配未包含的任意字符。{n}
:n 是一个非负整数。匹配确定的 n 次。{n,}
:n 是一个非负整数。至少匹配n 次。{n,m}
:m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。
次数通配符
在Java中,当我们谈论“次数通配符”时,实际上我们可能是在引用正则表达式中的量词(quantifiers),这些量词用于指定某个模式在字符串中出现的次数。然而,“次数通配符”这个术语并不是Java或正则表达式中的标准术语,但我们可以理解为它指的是用于指定字符或字符集出现次数的正则表达式组件。
在正则表达式中,这些“次数通配符”或量词包括:
-
*
- 匹配前面的子表达式零次或多次。例如,zo*
能匹配 "z" 以及 "zoo"。 -
+
- 匹配前面的子表达式一次或多次。例如,zo+
能匹配 "zo" 以及 "zoo",但不能匹配 "z"。 -
?
- 匹配前面的子表达式零次或一次。例如,do(es)?
可以匹配 "do" 或 "does" 中的 "do" 。 -
{n}
- n 是一个非负整数。匹配确定的 n 次。例如,o{2}
不能匹配 "Bob" 中的 "o",但是能匹配 "food" 中的两个 o。 -
{n,}
- n 是一个非负整数。至少匹配 n 次。例如,o{2,}
不能匹配 "Bob" 中的 "o",但能匹配 "foooood" 中的所有 o。 -
{n,m}
- m 和 n 均为非负整数,其中n <= m。最少匹配 n 次且最多匹配 m 次。例如,o{1,3}
将匹配 "fooooood" 中的前三个 o。
需要注意的是,这些量词(或“次数通配符”)并不是Java特有的,而是正则表达式语言的一部分,Java通过java.util.regex
包中的类(如Pattern
和Matcher
)提供了对正则表达式的支持。
在Java中使用这些量词时,你通常会将它们与Pattern
和Matcher
类一起使用,或者在某些情况下,直接使用String
类的matches()
, split()
, replaceAll()
等方法,这些方法内部也使用了正则表达式。
例如,使用Pattern
和Matcher
类来查找字符串中所有匹配特定模式的子串:
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class RegexExample {
public static void main(String[] args) {
String text = "Apple is round, apple is juicy, apple is sweet.";
String pattern = "apple";
Pattern p = Pattern.compile(pattern, Pattern.CASE_INSENSITIVE);
Matcher m = p.matcher(text);
while (m.find()) {
System.out.println("Found: " + m.group());
}
}
}
但是,如果你想要使用量词来指定apple
出现的次数(虽然在这个例子中可能不太适用),你需要在正则表达式中直接使用它们,比如apple+
来匹配一个或多个连续的"apple"(尽管这实际上会匹配到"appleapple"这样的字符串,而不是单独计算每个"apple"的出现次数)。
其他通配符
StringBuffer和StringBuilder
StringBuffer
和 StringBuilder
是 Java 中用于创建可修改的字符串的类,它们都位于 java.lang
包中。尽管它们有着相似的功能和用法,但它们之间还是存在一些关键的差异,主要体现在线程安全性和性能上。
线程安全性
- StringBuffer:是线程安全的。这意味着当多个线程同时访问同一个
StringBuffer
实例时,对字符串的修改操作是同步的,从而避免了数据不一致的问题。然而,这种线程安全性是以牺牲性能为代价的,因为每次修改操作都需要进行线程同步。 - StringBuilder:不是线程安全的。当在单线程环境下使用时,它比
StringBuffer
提供了更好的性能,因为它避免了不必要的线程同步开销。但是,如果你在多线程环境中使用StringBuilder
,并且多个线程可能会同时修改同一个StringBuilder
实例,那么就需要自己管理线程安全,否则可能会导致数据不一致。
性能
由于 StringBuilder
避免了 StringBuffer
中的线程同步开销,因此在单线程环境下,StringBuilder
的性能通常优于 StringBuffer
。但是,在多线程环境中,如果你选择使用 StringBuilder
并希望保持数据一致性,那么你可能需要手动实现线程同步,这可能会降低性能。
用法
在用法上,StringBuffer
和 StringBuilder
非常相似。它们都提供了 append()
、insert()
、delete()
等方法来修改字符串。但是,由于 StringBuilder
不是线程安全的,所以在多线程环境下使用时需要格外小心。
选择哪一个?
- 如果你在多线程环境下工作,并且需要确保字符串的线程安全性,那么应该选择
StringBuffer
。 - 如果你在单线程环境下工作,或者确信你的应用程序中的字符串不会被多个线程同时修改,那么应该选择
StringBuilder
以获得更好的性能。
示例
// 使用 StringBuffer
StringBuffer sb = new StringBuffer("Hello, ");
sb.append("World!");
System.out.println(sb.toString()); // 输出: Hello, World!
// 使用 StringBuilder
StringBuilder sbBuilder = new StringBuilder("Hello, ");
sbBuilder.append("World!");
System.out.println(sbBuilder.toString()); // 输出: Hello, World!
在这两个示例中,StringBuffer
和 StringBuilder
的用法几乎相同,但选择哪一个取决于你的具体需求和应用程序的上下文。