关于String的一些实用技能
一、String
面试经常会看到关于String,到底String是怎么一回事呢 ?
- String的常量池
JVM在堆中开辟了一段空间迎来缓存所有使用字面量
创建的字符串对象,只要发现已经创建过的字符串
字面量创建新字符串时,JVM会直接使用缓存的对象
而不是在创建新对象,这样做避免内存堆积大量
内容一样的字符串对象,降低内存开销
一、
//直接量 字面量
String s1 = "123abc";
String s2 = "123abc";//重用S1创建的对象
String s3 = "123abc";//一样重用
System.out.println(s1==s2);//true
System.out.println(s1==s3);//true
上边为什么会是true?
s1、s2、s3 三个里面内容是相同的;s3会利用之前(s1)的缓存123abc 。( s2同理 )
所以为true。
二、
String s1 = "123abc";
String s2 = "123abc";
//一旦修改内容,就会创建新对象
s1 = s1+"!";//s1不在指向原对象
System.out.println("s1:"+s1);//123abc!
System.out.println("s2:"+s2);//123abc
这个时候s1输出为 123abc!,会不在指向原对象。
三、
String s2 = "123abc";
//new是一个比较强制的操作,一定创建新对象
String s4 = new String("123abc");
System.out.println("s4:"+s4);
System.out.println(s2==s4);//false
这次会输出false,因为new是一个比较强制的操作,一定创建个对象。
虽然内容相同,但是两者对象不同,所以比较为false!
四、
/**
* 这里触发了编译器一个特点
* 编译器在编译代码时若出现一个表达式
* 参与的值都是字面量时,那么该计算表达式的结果
* 是确定的,此时编译器计算表达式的结果,将结果替换表达式
* 这样一来JVM每次执行字节码文件就不用计算了
* 下面的代码会被编译器编译后为:
* String s5="123abc";
*/
String s5 = "123"+"abc";
String s2 = "123abc";
System.out.println("s5:"+s5);
System.out.println(s2==s5);//true
上边说到了,编译器的特点。虽然两者是相加的,但表达式参与值为字面量,直接把结果确定;
两者对象比较,值相同,所以为false
五、
String s = "123";
String s6 = s+"abc";
System.out.println(s2==s6);//false
上边说到了,当使用了字面量时,会自动变为结果进行比较。
当使用了一个变量,不是字面量时。进行比较对象,为false!
二、String不适合频繁修改
字符串是不变对象,若想改变内容一定会创建新对象
这样的做法源自JVM对字符串的优化,但是这样的做法
弊端修改字符串时性能低下(虽然这样的操作不频繁)
频繁修改产生大量垃圾,内存开销大,运行效率差
结论:String不适合频繁修改
三、String、StringBuffer、StringBuilder区别
StringBuffer与StringBuilder相同点都是字符串变量,是可改变的对象,每当我们用它们对字符串做操作时,
实际上是在一个对象上操作的。String每次操作会创建一些新的对象,所以速度快些。
不同点是StringBuilder是线程非安全的,StringBuffer是线程安全的, 当我们在字符串缓冲区被多个线程使用时,
JVM不能保证StringBuilder的操作是安全的,虽然它的速度最快,但是可以保证StringBuffer是可以正确操作的。
当然大多数情况下我们是在单线程下进行的操作,所以大多数情况下建议使用StringBuilder而不用StringBuffer的,
就是速度的原因。
对于三者使用的总结:
1.如果要操作少量的数据使用 String。
2.单线程操作字符串缓冲区,操作大量数据使用 StringBuilder。
3.多线程操作字符串缓冲区,操作大量数据使用 StringBuffer。
--------------------------------------------------------
String的使用
1、 char charAt(int index)
-
下标 获取当前字符串中指定位置对应的字符
String str="thinking in java"; char c=str.charAt(9); System.out.println(c);//i
注意:第一个是从0开始数的。
这时会输出String str变量中的第九个下标对应的。
2、int indexOf(String str)
-
检定给定的当前字符串中的位置
-
若当前字符串不包含给定内容,则返回值为-1
String str="thinking in java"; //查找str中"in"所在的位置 int index = str.indexOf("in");//2 System.out.println(index); //从指定位置开始查找第一次出现"in"的位置 index = str.indexOf("in",3); System.out.println(index);//5 //查找最后一次出现"in"位置 index = str.lastIndexOf("in"); System.out.println(index);//9
3、int length()
-
获取当前字符串长度(字符个数)
String str = "我爱java!!"; int length = str.length(); System.out.println("len:"+length);//len:8
4、boolean startsEith(String str)
boolean endsWith(String str)
-
判断一个字符串是否以字符开始或结尾的
String str="thinking in java"; boolean starts =str.startsWith("thi"); System.out.println("start:"+starts);//true boolean ends =str.endsWith("ava"); System.out.println("ends:"+ends);//true
5、String substring(int start,int end)
-
截取指定范围内的字符串,两个参数分别表示下标
-
从start处开始,end结束(不包含end处的字符)
-
java API中的参数有一个特点,通常用两个数字表示
-
范围时都是“含头不含尾”的。
String str="eee.hhhh.com"; String sub=str.substring(4,8); System.out.println(sub);//hhhh //从指定位置开始截取到字符串末尾 sub=str.substring(4); System.out.println(sub);//hhhh.com
6、String toUpperCase()
String toLowerCase()
-
将当前英文字符部分转换为全大写或全小写
String str="我爱java,LALALA"; String upper =str.toUpperCase(); System.out.println(upper);//我爱JAVA,LALALA String lower=str.toLowerCase(); System.out.println(lower);//我爱java,lalala
7、String trim()
-
去除字符串两边的空白字符
String str=" h e l l o "; System.out.println(str); // h e l l o String trim=str.trim(); System.out.println(trim);//hello System.out.println(str.trim());//hello
这两个结果都是相同的,只是用法不一样。
8、static String valueOf(XXX xxx)
-
字符串提供了一组静态的重载的valueOf方法,作用
-
是将其他类型转换为字符串
int a=123; String s1=String.valueOf(a); System.out.println(s1);//123 double d=123.123; String s2=String.valueOf(d); System.out.println(s2);//123.123 String s3=a+""; System.out.println(s3);//123
补充StringBuffer的使用
String str="努力学习java";
StringBuilder b=new StringBuilder(str);
System.out.println(b);
增
/**
* 增
* append():将给定内容拼接到字符串末尾
*/
b.append(",为了找个好工作!");
//获取StringBuilder内部表示的字符串
str = b.toString();
System.out.println(str);
改
/**
* 改
* 怒力学习java,为了找个好工作!
* 怒力学习java,就是为了改变世界!
*/
b.replace(9,17,"为了改变世界!");
System.out.println(b);
删
/**
* 删
*/
b.delete(0,9);
System.out.println(b);
插
/**
* 插:
*/
b.insert(0, "活着,就是");
System.out.println(b);
StringBuilder修改字符串性能
StringBuilder builder = new StringBuilder("a");
for(int i=0;i<100000000;i++){
builder.append("a");
}
System.out.println("执行完毕!");
这样是在同一个变量改变,所以效率比较高,
StringBuufer是安全的,StringBuilder是不安全的。
---------------------------------------------------
String和正则表达式配合使用
关于正则表达式
大小写不同,意思也就不同
\w [a-zA-Z0-9_] 单词字符
\W 非单词字符
\d [0-9] 任意一个数字
\D 非数字
\s 空白
\S 非空白
1、 String支持正则表达式的方法一:
- boolean matches(String regex)
- 使用给定的正则表达式验证当前字符串是否符合格式
简单判断是否符合邮箱格式
//String email = "[email protected]";
String email="myweb/reg?username=xxx&password=xxx&....";
String regex="\\?";
/*
* \w+@[a-zA-Z0-9]+(\.[a-zA-Z]+)+;
* 使用字符串描述正则表达式
*/
//String regex="\\w+@[a-zA-Z0-9]+(\\.[a-zA-Z]+)";
boolean match=regex.equals(email);
if(match){
System.out.println("是邮箱");
}else {
System.out.println("不是邮箱");
}
2、 String 支持正则表达式方法二:
- String[] split(string regex)
- 将当前字符串按照满足正则表达式的部分进行拆分,
- 将拆分后的部分以数组形式返回
拆分小例子
String line = "abc123bcd456efg789hji";
/*
* 按照数字部分拆分,得到所有的字母部分
*/
//String []arr1=line.split("[0-9]+");
/**
* 如果在拆分中出现了可连接的可拆分项 时,他们中间会拆分一个空字符串。
* 如果字符串开始就是拆分项时,前面也会拆分出 一个空字符串
* 注意:如果是字符串末尾连续匹配拆分项,那么所有拆分出的空串全部忽略
*/
String []arr=line.split("[0-9]");
System.out.println(arr.length);
for(int i=0;i<arr.length;i++){
System.out.println(arr[i]);
}
String image ="123.png";
String []date=image.split("\\.");
image =date[1];
System.out.println(image);
3、 String 支持正则表达式三:
- String replaceALL(String regex ,String str)
- 将当前字符串中满足正则表达式部分替换为给定内容
替换小例子
String str1 = "abc123def456ghi789jkl";
/*
* 将数字部分替换为"#NUMBER#"
*/
String str = str1.replaceAll("[0-9]+","#NUMBER#");
System.out.println(str);
4、和谐用语
当使用不文明语句,可以判断是否符合条件,然后进行替换,
例子如下:
String regex = "(dsb|mdzz|cnm|wqnmlgb)";
String message = "wqnmlgb!cnm";
message = message.replaceAll(regex,"**");
System.out.println(message);