一、String
1) 分类
不可变的 String
可变的就是 StringBuffer、 StringBuilder
2) 理解
String a = “Hello”
a = “World” 不是将Hello 的值改变为 “World” 而是重新创建了一个”World “ 将地址给了a ;
<br /> ![image.png](https://cdn.nlark.com/yuque/0/2022/png/22131196/1646876806672-18736bde-aa10-4ee8-8932-94d8b8f9ff82.png#clientId=u38369c40-227b-4&crop=0&crop=0&crop=1&crop=1&from=paste&height=301&id=uf9074c8e&margin=%5Bobject%20Object%5D&name=image.png&originHeight=602&originWidth=957&originalType=binary&ratio=1&rotation=0&showTitle=false&size=33071&status=done&style=none&taskId=ucb5069e0-2981-4627-91a7-d65c1cdd8b1&title=&width=478.5)<br />3、equals
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 9:38
* @Version 1.0
*/
public class Demo01 {
/**
*
* String 是不可变的字符串
* 1、理解 "Hello" 这个字符串在jvm中的值是不会改变的
*/
public static void main(String[] args) {
String a = "Hello" ;
// String a = "Hello"
// a = "World"
// 不是将Hello 的值改变为 “World" 而是重新创建了一个”World " 将地址给了a ;
// a = "world" ;
String b = "Hello" ;
// 当 a = "Hello" 赋值的时候会先从常量池的查找是否有"Hello" 如果没有,创建”Hello" 字符串
// 赋值给 a ,当下一次 b = "Hello" 就从字符串常量池寻找“Hello" 进行赋值,所以
// a 和 b 在内存中的地址是一样的
System.out.println(a==b);
// "Hello" "World"
/**
* equals 本身是Object 父类的方法
* String 也是Object 的子类
* String 重写了 equals
* 原理是:先判断长度是否相同,长度相同; 将两个字符串全部变为字符数组
* char[] arr = {'H','e','l','l','o'}
* 进行循环比对,只要有一位不一样,直接返回false
*/
System.out.println(a.equals(b));
}
}
4、享元原则以及效率对比
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 9:59
* @Version 1.0
*/
public class Demo02 {
/**
* 字符串的值为什么要放在 常量池 中呢?
* 享元原则 --> 经常用到的内容 放在一个地方,进行多方面的共享
*/
public static void main(String[] args) {
/**
* 先将数值类型的10 放在一个数组中,下一次又遇到了 10 ,直接取出来
* [-128,127)
*/
Integer i = Integer.valueOf(10);
Integer i2 = Integer.valueOf(10);
System.out.println(i == i2);
Integer i3 = Integer.valueOf(200);
Integer i4 = Integer.valueOf(200);
System.out.println(i3 == i4);
String a = "bigdata";
String b = "bigdata";
/**
* a,b 指向的是常量池中的 “bigdata" 所对应的地址
*/
String aa = new String("bigdata");
String bb = new String("bigdata");
/**
* 以上代码创建了两个对象 堆 & 常量池中
* aa 指向了堆中的一个 实例化对象,实例化中的指针,指向了常量池中的 “bigdata"地址
* bb 指向了堆中的一个 实例化对象,实例化中的指针,指向了常量池中的 “bigdata"地址
*/
System.out.println(aa == bb);
/**
* String a = "bigdata";
* 效率要高于
* String a =new String("bigdata");
*/
}
}
5、字符串拼接
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 10:15
* @Version 1.0
*/
public class Demo03 {
public static void main(String[] args) {
// a 指向的是 在常量池中进行拼接以后的第三个字符串 "HelloWorld"
String a = "Hello" + "World" ;
String b = new String("Hello");
String c = new String("World");
String d = b + c ;// d 指向的是不是常量池中拼接以后的地址
//在这个拼接的过程中, 隐式的实例化了一个String类的对象, 在堆上开辟了空间。
// 堆上空间内部维护了一个指向了常量池中拼接结果的一个属性。 这个堆上的空间地址给左侧的引用进行了赋值
System.out.println(a == d);
String e = new String("Hello") + "World" ; // 会产生新的对象的
System.out.println(e == d); // false
System.out.println(e == a); // false
}
}
6、字符串的构造方法
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 10:58
* @Version 1.0
*
* String 的构造方法
*/
public class Demo04 {
public static void main(String[] args) {
String s = new String(); // String s = "";
System.out.println(s);
String s1 = new String("abc"); // String s1 = "abc"
System.out.println(s1);
System.out.println(s1.toString());
char[] sArr = {'H','e','e','A','B'};
String s2 = new String(sArr);
System.out.println(s2);
System.out.println(new String(sArr, 2, 3));
// 作用不是特别大,了解一下
byte[] sArr2 ={122,93,89};
String s3 = new String(sArr2);
System.out.println(s3);
}
}
7、常用方法
package com.qfedu.day08_01;
import java.util.Arrays;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 11:14
* @Version 1.0
*/
public class Demo05 {
public static void main(String[] args) {
char[] sArr = {'H','e','e','A','B'};
System.out.println(new String(sArr));
String s = "hello" ;
// 将字符串变为数组
char[] array = s.toCharArray();
System.out.println(Arrays.toString(array));
// 获取字符串中某个位置的字符,从0 开始的
System.out.println(s.charAt(0));
// 比较两个字符串(按照字典顺序)
// Hello Hallo
/**
* 依次比对各个位数上的字典顺序,如果返回 正数说明前面的大有后面的
* 小于就是后面的大于前面的,等于0 说明两个字符串相等。
*/
System.out.println("Hello".compareTo("Hallo"));
System.out.println("Hello".compareTo("Hello"));
System.out.println("Hello".equals("Hello"));
System.out.println("Hello".compareTo("hello"));
System.out.println("Hello".compareToIgnoreCase("hello"));
// 字符串拼接
/**
* 五种字符串的拼接方式,将来最一个性能分析:
*
* String a = "abc"+"bcd"
* String a = new String("abc") + new String("bcd")
* String a = "abc".concat("cbd")
*/
System.out.println("abc".concat("cbd"));
// public interface CharSequence String 就是这个接口的实现类
// 字符串中是否包含另一个字符串
System.out.println("Hello".contains("o"));// boolean
//System.out.println("Hello".contains('o'));
// 字符串中第一次出现另个字符串的下标
System.out.println("Hello".indexOf("a")); // 返回下标 存在 返回 >= 0 的数 ,不存在,返回 -1
System.out.println("Hello".indexOf("ll")); // 返回 2
/**
* 不重要
* 将char[] 数组变为 字符串
*/
System.out.println(String.valueOf(sArr));
System.out.println(String.copyValueOf(sArr));
/**
* 字符串是否以某个字符串结尾
*/
System.out.println("Hello".endsWith("o"));
System.out.println("Hello".endsWith("lo"));
System.out.println("ABC".equals("abc"));
/**
* 忽略大小写比较,内容比较
*/
System.out.println("ABC".equalsIgnoreCase("abc"));
/**
* format
* %s --> 字符串
* %ns --> 长度为n的字符串
* %d --> 整数
* %nd --> n位 的整数
* %.nf --> 精确到小数点后n位的小数
*/
String ss = String.format("姓名是:%s,年龄是%d,考了%.2f分","小明",20,88.5789);
System.out.println(ss);
String ss2 = String.format("姓名是:%10s,年龄是%5d,考了%.2f分","小明",20,88.5789);
System.out.println(ss2);
// indexOf 第一次出现的下标位置是多少
/**
* 如果传递的是一个int类型的参数,先将参数转换为对应的char,再查找
*/
System.out.println("Hello".indexOf(72));
System.out.println("Hello".indexOf("o"));
System.out.println("Hello".indexOf("l")); // 2
System.out.println("Hello".indexOf("l",3));// 3
String str = "";
System.out.println(str.isEmpty());
String str2 = " "; // 长度是1
System.out.println(str2.isEmpty());
String str3 = null;
// Exception in thread "main" java.lang.NullPointerException
// 任何一个null 的对象,调用任何方法,都会报 空指针异常
// 如果出现空指针,定位到代码处,只有两个地方会出现 80% 是前面,20% 是参数
System.out.println(str3.isEmpty());
}
}
如何自定义判断一个字符串是否为空 isEmpty()
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 14:39
* @Version 1.0
*/
public class StringUtils {
/**
* 判断一个字符串是否为空
*/
public static boolean isEmpty(String str){
// 先判断是否为null
if(str != null && !str.equals("") && !str.equals("null")){
return false;
}
return true;
}
// 错误演示,一定要先判断是否为null 才行
/*public static boolean isEmpty(String str){
// 先判断是否为null
if( !str.equals("") && !str.equals("null") && str != null ){
return false;
}
return true;
}*/
public static void main(String[] args) {
isEmpty(null);
}
}
package com.qfedu.day08_01;
import java.util.Arrays;
import java.util.Scanner;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 14:48
* @Version 1.0
*/
public class Demo06 {
/**
* String 常用方法
* @param args
*/
public static void main(String[] args) {
/*
将多个字符串拼接为新的字符串,可以指定拼接符
*/
String message = String.join("~", "Java", "is", "cool");
System.out.println(message);
/**
* 从最后往前看,出现第一次字符串的下标是多少
* indexOf 是一样的,只有查找的方向不一样
*/
System.out.println("Hello".lastIndexOf("l"));// 3
/**
* 返回字符串的长度
*/
System.out.println("Hello".length());
String[] arr = new String[8];
System.out.println(arr.length);
/*Scanner scanner = new Scanner(System.in);
System.out.println("请输入一个数字:");
int i = scanner.nextInt();
System.out.println(i);*/
String a = "Hello World Zhangsan Ni Hao";
String replaceStr = a.replace(" ", "##");
System.out.println(replaceStr);
// 替换所有的符合内容的地方,替换成新的字符串
System.out.println(a.replaceAll(" ", "**"));
// 通过某个规则进行切割,切割完之后返回数组
String[] arrStr = a.split(" ");
System.out.println(Arrays.toString(arrStr));
System.out.println("Hello".startsWith("He"));
/**
* subString 截取
*
* 从什么位置开始截取(包含)
* 到什么位置结束 (不包含)
*/
System.out.println("Hello".substring(1,4));
// 如果只输入一个值,说明从这个下标开始,截取到最后一个
System.out.println("Hello".substring(1));
// 将字符串中的所有字符全部转为小写
System.out.println("Hello".toLowerCase());
// 将字符串中的所有字符全部转为大写
System.out.println("Hello".toUpperCase());
System.out.println("闫".toLowerCase());// 无变化,原样输出
/**
* "Hello ".equals("Hello") false
*/
System.out.println("Hello ".trim());
System.out.println(" Hello World ".trim());
System.out.println("Hello".trim());
System.out.println(String.valueOf(1));
}
}
replace 和 replaceAll
/**
* replace(old,new) 是全部替换
* replaceAll(正则表达式,new) 是全部替换
*/
String ss = " Hello World ";
System.out.println(ss.replace(" ","*"));
String regex = "\\s" ; // 匹配 空白(空格\tab) //
System.out.println(ss.replaceAll(regex,"#"));
//System.out.println(ss.replace(regex,"*")); // 不报错,没作用
二、StringBuffer和StringBuilder类
作用:可变字符串
StringBuffer : 线程安全的,但是效率不及StringBuilder
StringBuilder : 线程不安全的,效率高。
字符串内容拼接效率对比:
效率: 1、字符串通过+ 进行拼接效率非常的慢。
原因是:会在常量池中创建大量的一次性的常量,而且还得回收。
2、StringBuilder 效率要高于 StringBuffer
底层原理: 通过数组进行存储的
1) char[] a = new char[100] ;
append 方法 ,就将这个字符 放入数组中。
2) 如果一旦满了,就自动扩容。创建新的数组,将老的数组的值赋值给新数组,进行在新的数组中存放内容
* 不需要创建大量的对象,效率比较高。
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 16:10
* @Version 1.0
*
* 效率: 1、字符串通过+ 进行拼接效率非常的慢。
* 原因是:会在常量池中创建大量的一次性的常量,而且还得回收。
* 2、StringBuilder 效率要高于 StringBuffer
* 底层原理: 通过数组进行存储的
* 1) char[] a = new char[100] ;
* append 方法 ,就将这个字符 放入数组中。
* 2) 如果一旦满了,就自动扩容。创建新的数组,将老的数组的值赋值给新数组,进行在新的数组中存放内容
* 不需要创建大量的对象,效率比较高。
*/
public class Demo08 {
public static void main(String[] args) {
long begin = System.currentTimeMillis();
String a = " ";
// 执行你像看到的代码
for (int i = 0; i < 100000; i++) {
a += i;
}
long end = System.currentTimeMillis();
System.out.println("通过字符串+J进行运算的执行时间:"+(end-begin));
long begin2 = System.currentTimeMillis();
StringBuffer sb = new StringBuffer();
// 执行你像看到的代码
for (int i = 0; i < 100000; i++) {
sb.append(i);
}
long end2 = System.currentTimeMillis();
System.out.println("通过StringBuffer进行运算的执行时间:"+(end2-begin2));
long begin3 = System.currentTimeMillis();
StringBuilder sb2 = new StringBuilder();
// 执行你像看到的代码
for (int i = 0; i < 100000; i++) {
sb2.append(i);
}
long end3 = System.currentTimeMillis();
System.out.println("通过StringBuilder进行运算的执行时间:"+(end3-begin3));
}
}
三、正则表达式
独立的技术: 编写好了一个正则表达式,可以作用与任何的开发语言,不仅仅是java。
元字符 | 意义 |
---|---|
^ | 匹配一个字符串的开头。 在Java的正则匹配中,可以省略不写。 |
$ | 匹配一个字符串的结尾。 在Java的正则匹配中,可以省略不写。 |
[] | 匹配一位字符。 [abc]: 表示这一位的字符, 可以是a、也可以是b、也可以是c 。 [a-z]: 表示这一位的字符, 可以是 [a, z] 范围内的任意的字符。 [a-zABC]: 表示这一位的字符, 可以是 [a,z ] 范围内的任意字符, 或者A、或者B、或者C 。 [a-zA-Z]: 表示这一位的字符, 可以是任意的字母, 包括大写字母和小写字母。 [^abc]: 表示这一位的字符, 可以是除了 a、b、c 之外的任意字符。 [^a-z[hk]]: 表示这一位的字符, 不能是任意的小写字母, 但是 h 、 k 除外。 |
\ | 转义字符。 由于正则表达式在Java中是需要写在一个字符串中。 而字符串中的\也是一个转义字符。 因此Java中写正则表达式的时候, 转义字符都是 \\ 使得某些特殊字符成为普通字符, 可以进行规则的指定。 使得某些普通字符变得具有特殊含义。 |
\d | 匹配所有的数字, 等同于 [0-9] 。 |
\D | 匹配所有的非数字, 等同于 [^0-9] 。 |
\w | 匹配所有的单词字符, 等同于 [a-zA-Z0-9_] 。 |
\W | 匹配所有的非单词字符, 等同于 [^a-zA-Z0-9_] 。 |
. | 通配符, 可以匹配一个任意的字符。 |
+ | 前面的一位或者一组字符, 连续出现了一次或多次。 |
? | 前面的一位或者一组字符, 连续出现了一次或零次。 |
* | 前面的一位或者一组字符, 连续出现了零次、一次或多次。 |
{} | 对前面的一位或者一组字符出现次数的精准匹配。 {m} : 表示前面的一位或者一组字符连续出现了m次。 {m,} : 表示前面的一位或者一组字符连续出现了至少m次。 {m,n} : 表示前面的一位或者一组字符连续出现了至少m次,最多n次。 |
| | 作用于整体或者是一个分组, 表示匹配的内容, 可以是任意的一个部分。 abc|123|opq : 表示整体的部分, 可以是 abc, 也可以是 123, 也可以是 opq |
() | 分组。 把某些连续的字符视为一个整体对待。 |
正则表达式训练:
/**
* @Author 千锋大数据教学团队
* @Company 千锋好程序员大数据
* @Date 2020/4/15
* @Description 正则表达式的基础语法
*/
public class Regex2 {
public static void main(String[] args) {
// 校验规则:
System.out.println(",ello".matches("[ahj1,8]ello"));
System.out.println("fello".matches("[a-z]ello"));
// 需求: 首位字符,可以是任意的小写字母,或者是 HAQ
System.out.println("Hello".matches("[Ha-zAQ]ello"));
// 需求: 首位字符,可以是任意的字母,包括大写字母和小写字母
System.out.println("hello".matches("[a-zA-Z]ello"));
// 需求: 首位字符,可以是除了h之外的任意字符
System.out.println("Hello".matches("[^hel]ello"));
// 需求: 首位字符,不可以是任意的小写字母,但是 h、e、q 除外
System.out.println("lello".matches("[^a-z[heq]]ello"));
// 希望首位字符,可以是 h e [
System.out.println("]ello".matches("[he\\[]ello"));
// 希望首位字符,可以是 a - z
System.out.println("hello".matches("[az-]ello"));
System.out.println("hello".matches("hel+o"));
System.out.println("hello".matches("hel?o"));
System.out.println("heo".matches("hel*o"));
System.out.println("hello".matches("hel{3}o"));
System.out.println("hello".matches("hel{3,}o"));
System.out.println("hello".matches("hel{3,5}o"));
// 需求: 匹配一个字符串可以是 126 或者是 163 或者是 qq 或者是 QQ
System.out.println("123".matches("126|163|qq|QQ"));
// 需求: 匹配一个qq邮箱、126邮箱、163邮箱
System.out.println("admin@sina.com".matches("admin@(qq|126|163)\\.com"));
}
}
正则表达式实战:
package com.qfedu.day08_01;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 17:36
* @Version 1.0
*/
public class Demo10 {
public static void main(String[] args) {
String regex = "1[356789][0-9]{9}";
System.out.println("18638147931".matches(regex));
System.out.println("1863814793".matches(regex));
System.out.println("14638147931".matches(regex));
// xxxxx@qq.com
// ssss@163.com
// 343434@gmail.com
// yanzhenwei@1000phone.net
String regexEmail = "\\w+@[a-zA-Z0-9]+\\.(com|cn|net)";
System.out.println("yanzhenwei@1000phone.net".matches(regexEmail));
System.out.println("2384723432@qq.com".matches(regexEmail));
System.out.println("2d3re4qw@163.com".matches(regexEmail));
System.out.println("18137884406@126.net".matches(regexEmail));
System.out.println("18137884406@126.con".matches(regexEmail));
System.out.println("YNDJKSJK126.con.com".matches(regexEmail));
}
}
正则表达式的另一种匹配方式:
package com.qfedu.day08_01;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* @Author laoyan
* @Description TODO
* @Date 2022/3/10 17:36
* @Version 1.0
*/
public class Demo11 {
public static void main(String[] args) {
String regex = "1[356789][0-9]{9}";
Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher("18638147931");
System.out.println(matcher.matches());
//以上代码相当于
System.out.println("18638147931".matches(regex));
}
}