字符串
是由若干个字符组成的一个有序的序列。在Java中,使用String这个类来描述字符串。
java.lang.String 使用final修饰,不能被继承
字符串底层封装的是字符数组及其针对数组的操作方法
字符串一旦创建,对象永远无法改变,但字符串引用可以重新赋值
字符串在内存中采用Unicode编码方式,任何一个字符对应两个字节的定长编码
字符串的索引值从0开始
public class StringDemo01 {
public static void main(String[] args) {
String name = "hello"; // ['h','e','l','l','o']
String name1 = new String("hello");
String name2 = new String("hello");
System.out.println(name1 == name2);
String name3 = name+1; //hello这个对象 和1拼接后,产生了一个新的对象
System.out.println(name == name3);
}
}
字符串常量池
JVM为了提升性能和减少内存开销,避免重复创建字符串,其维护了一块特殊的内存空间,即字符串常量池。
当需要使用静态字符串(字面量/常量/常量连接的结果)时,先去检查字符串常量池是否存在该字符串,若存在,则直接返回该字符串的引用地址;若不存在,则在字符串常量池中创建字符串对象,并返回对象的引用地址。
public class StringDemo02 {
public static void main(String[] args) {
String str1 = "hello";//程序启动后,常量池中是没有hello的,要将hello创建到常量池中,地址返回
String str2 = "hello"; //先去常量池中寻找是否有该样子的对象,发现是有的,因此返回常量池中的该对象的地址
System.out.println(str1 == str2); //因为两个变量指向的是同一个对象,地址一定是一样的。所以true.
String str3 = "helloworld";
String str4 = "hello" + "world"; //两个字面量做拼接操作时,javac期间会直接返回结果 "helloworld"
System.out.println(str3 == str4);//true
String str5 = str1 + "world"; // 如果是变量参与拼接运算,javac期间并不会优化,而是在运行期间拼接的。
System.out.println(str4 == str5);//false
String str6 = new String("hello");
System.out.println(str1 == str6); //false
String str7 = new String("hello");
System.out.println(str1 == str7); //false
System.out.println(str6 == str7);//false
}
}
其内存位置:
在 JDK 1.7 之前,运行时常量池(包括字符串常量池)存放在方法区。
在 JDK 1.7 时,字符串常量池被从方法区转移至 Java 堆中,注意并不是运行时常量池,而是字符串常量池被单独转移到堆,运行时常量池剩下的东西还是方法区中。
在 JDK 1.8 时,此时字符串常量池还在堆中。
常用构造器
空参构造器:
String():
初始化一个新创建的空字符序列的字符串对象
// 构建一个字符串对象,可以直接静态初始化字面量
String str1 = "helloworld";
String str2 = "";
String str3 = new String();
System.out.println(str3.equals(str2)); //true
传字节数组的构造器:
String(byte[] bs)
使用默认编码集解码byte数组,构建一个字符串对象
byte[] bts = {67, 68, 69, 70, 71, 72, 73, 74};
String s = new String(bts);
System.out.println(s);
// String(byte[] bs): 会将字节数组按照默认的字符集转成字符串。 通常默认的字符集是UTF-8.
// UTF-8字符集: 汉字是三个字节。 字母是一个。
byte[] bts2 = {-28, -72, -83, -27, -101, -67,-27, -91, -67};
String s2 = new String(bts2);
System.out.println(s2);
String(byte[] bs,String charsetName)
使用指定编码集charsetName 解码byte数组,构建一个字符串对象
byte[] bytes = {72, 101, 108, 108, 111};
String charsetName = "UTF-8";
String str = new String(bytes, charsetName);
System.out.println(str); // Output: Hello
String(byte[] bs,int offset,int length)
使用默认编码集解码byte数组的从offset开始,length个元素,构建一个字符串对象
byte[] bytes = {72, 101, 108, 108, 111, 44, 32, 87, 111, 114, 108, 100, 33};
String str1 = new String(bytes, 0, 5);
System.out.println(str1); // Output: Hello
String str2 = new String(bytes, 7, 5);
System.out.println(str2); // Output: World
String(byte[] bs,int offset,int length,String charsetName)
初始化一个字符串对象,使其字符序列包含参数的元素
String str3 = new String(bytes, 0, bytes.length, "UTF-8");
System.out.println(str3); // Output: Hello, World!
传字符数组的构造器
String(char[] cs)
初始化一个字符串对象,使其字符序列包含参数的元素
char[] charArray = {'H', 'e', 'l', 'l', 'o'};
String str = new String(charArray);
System.out.println(str); // Output: Hello
常用方法
length方法
length()方法可以获取字符串对象的字符个数。
一定要注意,数组的元素个数的获取方式是 引用.length, 不是方法,是属性
String obj = "你好,HelloWorld";
System.out.println(obj.length()); //13
indexOf方法实现检索
String类型提供了几个重载的indexOf方法
int indexOf(String str)
int indexOf(String str,int fromIndex)
作用:用于返回指定字符串在此字符串中第一次出现的索引,找不到返回-1
String还定义了lastIndexOf方法
int lastIndexOf(String str)
int lastIndexOf(String str,int endIndex)//从0处开始向后找到指定位置
作用:用于返回指定字符串在此字符串中最后一次出现的索引,找不到返回-1
String line = "no zuo no die";
System.out.println("line的长度是:"+line.length());
//获取zuo在line的哪个位置上,从0开始
int i = line.indexOf("zuo");
System.out.println("出现的位置:"+i);
int i1 = line.indexOf("o", 3);
System.out.println(i1);
int i2 = line.indexOf('S', 3);
System.out.println(i2);
System.out.println("o最后一次出现的位置:"+line.lastIndexOf('o',6));
使用substring获取子串
常用重载方法:
String substring(int beginIndex)
String substring(int beginIndex,int endIndex)
作用:substring方法用于返回一个字符串的子字符串
// 获取"zuo no"
String sub1 = line.substring(3, 9);
System.out.println("获取的子串:"+sub1);
sub1 = line.substring(7);
System.out.println("获取的子串:"+sub1);
trim截掉空格
String trim()
作用:去掉一个字符串的前与后的空字符,不会去掉中间的空字符
line = " hello kitty ";
System.out.println("line的长度:"+line.length());
System.out.println(line.trim());
charAt获取字符
char charAt(int index)
作用:返回指定索引处的char值
//获取索引3处的字符
char c = line.charAt(3);
System.out.println("c:"+c);
startsWith和endsWith
boolean startsWith(String str)
boolean endsWith(String str)
作用:检查一个字符是否以指定的字符串为前缀或后缀
//判断line是不是一个网址:
System.out.println("line是否为一个网址:"+line.startsWith("http://"));
line = "http://www.baidu.com";
System.out.println("line是否为一个网址:"+line.startsWith("http://"));
//查看字符串是否为一个qq邮箱
System.out.println("line是否为一个网址:"+line.endsWith("qq.com"));
line = "mmforu@qq.com";
System.out.println("line是否为一个网址:"+line.endsWith("qq.com"));
大小写变换
String toUpperCase()
String toLowerCase()
作用:对字符串中的字母进行转换成全部大写或全部小写
line = "AbcDefG";
String upperCase = line.toUpperCase();
System.out.println(upperCase);
String lowerCase = line.toLowerCase();
System.out.println(lowerCase);
toCharArray
char[] toCharArray()
作用: 将字符串转变成字符数组
line = "hello"; // ['h','e']
char[] charArray = line.toCharArray();
System.out.println(Arrays.toString(charArray));
valueOf
static String valueOf(int value)
static String valueOf(double d)
static String valueOf(char[] ch)
static String valueOf(Object obj)
作用:将其他类型转换成字符串类型
//将 int类型的1001, 转成字符串"1001" 3.14转成字符串"3.14" {'h','e'} 转成字符串 "he"
int age = 1001;
String s = String.valueOf(age);
String s1 = String.valueOf(3.14);
String s2 = String.valueOf(new char[]{'h', 'e'});
System.out.println(s+","+s1+","+s2);
equals与==
字符串类型中也重写了equals方法,用来比较两个字符串的相同位置上的内容是否相同,有一个不一致就直接返回false
boolean equals(String str)
- equals方法用于判断两个字符串的内容是否一样
- ==用于判断两个字符串是不是同一个对象(用来比较两个变量里的地址是否相同 )
//用户输入的用户名
String username = "zhangsan";
//模拟从数据库中获取的用户名
String user = new String("zhangsan");
//需要校验两个名字是否相同
System.out.println(username.equals(user));
StringBuilder和StringBuffer
String类型,如果频繁的拼接,会造成大量的垃圾对象,因为对象是不可变的,拼接操作会产生新对象。
可以使用其他的某些类,来实现高效率的字符串的操作:StringBuilder和StringBuffer。
StringBuilder和StringBuffer,都是一个可变的字符序列(即可变的字符串),对象创建后可以通过调用方法来实现字符序列的改变,StringBuilder和StringBuffer类中的方法完全相同。
区别:
StringBuilder是线程不安全的,效率高
StringBuffer是线程安全的,效率低
常用构造器
StringBuilder()
构造一个不带任何字符的字符串生成器,其初始容量为16个字符
可变字符串类型StringBuilder类型
StringBuilder builder = new StringBuilder();
StringBuilder(String str)
构造一个字符串生成器,其初始化为指定的字符串内容
StringBuilder bs = new StringBuilder("baidu");
常用方法
append方法
StringBuilder append(boolean b)
StringBuilder append(String str)
可以连续调用
作用:将指定字符串追加到字符串之后
StringBuilder a = builder.append("中国");
System.out.println(a);
//追加"是伟大的"
builder.append("是伟大的");
System.out.println(builder);
builder.append("国家").append(",是世界上").append("文明最悠久的").append("国家");
System.out.println(builder);
insert方法
StringBuilder insert(int index,String str)
作用:将指定字符串插入到字符串的指定索引处
StringBuilder bs = new StringBuilder("baidu");
bs.insert(0,"www.");
System.out.println(bs);
bs.append(".com").insert(bs.length(),".cn");
System.out.println(bs); // www.baidu.com.cn
delete方法
StringBuilder delete(int start , int end)//包前不包后
作用:删除字符串中的一部分
bs.delete(10,13);
System.out.println(bs);
bs.delete(3,4).delete(8,10);
System.out.println(bs);
reverse方法
StringBuilder reverse()
作用:将字符序列进行反转(左右颠倒)
bs.reverse();
System.out.println(bs);
String result = bs.toString();
System.out.println(result);
toString方法
String toString()
作用:将StringBuilder对象转变成String对象
String a1 ="hello";
String b1 = "world";
String c1 = a1+b1;
System.out.println(c1);
三者区别
-
StringBuilder是可变字符串,如果进行字符串的内容计算,建议选择StringBuilder,这样性能更好一些。
-
java的字符串连接的过程是利用StringBuilder实现的
-
StringBuilder 也是final修饰的类型,不能被继承
-
StringBuilder没有重写equals方法
-
StringBuilder是非线程安全的,并发处理,性能稍快
-
StringBuffer是线程安全的,同步处理,性能稍慢
正则表达式
**正则表达式(Regular Expressions),是一个特殊的字符串,可以对普通的字符串进行校验检测等工作。**正则表达式不是Java特有的,它是一套独立的语法,可以在java,c++,python等语言中使用。
正则表达式,最基本的使用场景是用来做校验,校验一个字符串是否满足预设的规则。在校验的基础 上,又添加了若干个其他的引用场景,例如: 批量的查找、替换、切割...
基本语法:
字符串集合
[] : 表示匹配括号里的任意一个字符。
[abc] :匹配a 或者 b 或者 c
//boolean matches(String regex):
//用来检验this是否符合regex这个正则表达式
//返回true符合 反之不符合
[^abc] : 匹配任意一个字符,只要不是a,或b,或c 就表示匹配成功
[a-z] : 表示匹配所有的小写字母的任意一个。
[A-Za-z] :表示匹配所有的小写字母和大写字母的任意一个。
[a-zA-Z0-9]:表示匹配所有的小写字母和大写字母和数字的任意一个。
[a-z&&[^bc]] :表示匹配所有的小写字母除了b和c, 只要匹配上就是true.
预定义字符集
转义字符:在编程语言中,有一些符合比较特殊,不会被编译语言当初普通字符来使用,如果非要当成普通字符来使用,必须在其前面添加一个反斜杠
\d: 用于匹配数字字符中的任意一个 相当于[0-9]
\w: 匹配单词字符中的任意一个 单词字符就是[a-zA-Z0-9_]
\D: 用于匹配非数字字符中的任意一个 相当于[^0-9]
\W: 用于匹配非单词字符中的任意一个
\s: 用于匹配空格,制表符(\t),退格符(\b),换行符(\n)等中的任意一个
\S: 用于匹配非空格,制表符,退格符,换行符等中的任意一个
. : 用于匹配任意一个字符(不需要转义)
javapublic static void main(String[] args) { //使用正则表达式语法,来定义一个规则 String regex = "[abc]"; String line = "ab"; /** * boolean matches(String regex): * 用来检验this是否符合regex这个正则表达式。 * 返回true,表示符合。 false表示不符合 */ if(line.matches(regex)){ System.out.println("符合规则"); }else{ System.out.println("不符合规则"); } regex = "[a-zA-Z0-9]"; System.out.println("_".matches(regex)); //验证:用户不能输入敏感字 X,中,国 regex = "[^X中国]"; System.out.println("中".matches(regex)); //验证: 用户只能输入A-Z,0-9,但是不能输入里面的W,X,5,8 regex = "[A-Z0-9&&[^WX58]]"; System.out.println("C".matches(regex)); System.out.println("-----------------预定义字符集----------------------"); //转义字符: 在编程语言中,有一些符合比较特殊,不会被编译语言当成普通字符来使用,如果非要当成普通字符来使用,必须在其前面添加一个反斜杠 // 这个反斜杠,我们称之为转义字符。 regex = "\\d"; System.out.println("a".matches(regex)); regex = "\\D"; System.out.println("a".matches(regex)); regex = "\\w"; System.out.println("-".matches(regex)); regex = "\\W"; System.out.println("-".matches(regex)); /** * \t: 制表符 * \n: 换行符 * \r: 回车符 * \b: 退格符 */ regex = "\\s"; System.out.println("\t".matches(regex)); regex = "\\S"; System.out.println("+".matches(regex)); regex = "."; // 注意: 表示任意字符时 点不需要转义,如果需要使用普通字符串点,需要添加转义字符 System.out.println("a".matches(regex)); }
数量词
X? :匹配0个或1个 [a]? a可有可无
X* :匹配0个或1个以上
x+ :匹配1个以上
X{n} :匹配n个
X{m,}:匹配m个以上 [\\w]{5,} 5个以上的单词字符
X{m,n}:匹配m~n个
javapublic static void main(String[] args) { //规则:a这个字符可有可无 String regex = "[a]?"; System.out.println("".matches(regex)); //true System.out.println("a".matches(regex)); //true System.out.println("b".matches(regex)); //false regex = "[a]?b"; System.out.println("ab".matches(regex)); System.out.println("b".matches(regex)); regex = "abc"; System.out.println("xxx".matches(regex));//false System.out.println("ab".matches(regex)); //false System.out.println("abc".matches(regex)); //true regex = "[a-z][a-z]"; System.out.println("xy".matches(regex)); //true //注册的名字是6个单词字符 regex = "[\\w][\\w][\\w][\\w][\\w][\\w]"; System.out.println("hello1".matches(regex)); //true regex = "[\\w]*"; System.out.println("hello1".matches(regex)); regex = "[\\w]+"; System.out.println("a".matches(regex)); regex = "[\\w]{5}"; System.out.println("hello1".matches(regex));//false System.out.println("abcde".matches(regex)); //true regex = "[\\w]{5,}"; System.out.println("hello1".matches(regex));//true //用户名可以使用5~8个单词字符 regex = "[\\w]{5,8}"; System.out.println("zhangsan".matches(regex));//true System.out.println("zhang+".matches(regex));//false }
分组()
想要检验的普通字符串可能符合某一个要求,或者是另外一个要求,此时
正则表达式需要使用分组符号(),来表示这些规则
在正则表达式上可以使用()来进行对一些字符分组,并可以使用逻辑运算符|来进行选择匹配
()里是成员,成员之间使用 或 来连接
reg:
String regex = "(135|137)[\\d]{8}" //匹配手机号是135或者是137开头的
javapublic static void main(String[] args) { //要求: 客户输入的手机号必须是137,158,182开头的手机号 String regex = "1(37|58|82)\\d{8}"; System.out.println("18211112222".matches(regex)); //要求: 判断客户输入的是不是一个网址 www.baidu.com String regexAddress = "(http[s]?://)?www\\.[\\w]+(\\.(com|cn|net))+"; String address = "www.baidu.com"; if(address.matches(regexAddress)){ System.out.println("是一个网址"); }else{ System.out.println("不是一个网址"); } }
^和$
^:表示严格从头匹配
$: 表示匹配到结尾
Java语言底层默认使用^开头,并且是$结尾的,即严格从头到尾进行校验
javapublic static void main(String[] args) { String regex = "[abc]{5,8}$"; String line = "xabbbbb"; System.out.println(line.matches(regex)); //底层在正则表达式前添加了^ }
常用方法
- boolean matches(String regex)
判断this字符串是否匹配正则表达式regex
- String[] split(String regex)
对this使用匹配上正则表达式的子串 进行切分 成字符串数组
- replaceAll()
替换 前面写旧的 后面写新的
//去掉字符串中的空格,使用空字符串替换调空格部分
public static void main(String[] args) {
String line = "no zuo no die ";
String regex = " ";
String[] split = line.split(regex);
System.out.println(Arrays.toString(split));
for (int i = 0; i < split.length; i++) {
System.out.println(split[i].length());
}
// 去掉字符串中的空格。使用空字符串替换掉符合正则表达式的子串部分
String s = line.replaceAll("[ ]+", "");
System.out.println(s);
}