Java知识点总结【4】String
1.String的创建
1)String str1="hello";
2)String str2=new String("hello");
3)通过char[]或者byte[]的方式来构造字符串
char[] arr={'h','e','l','l','o'};
String str3=new String(arr);
其中第一种方式最常用,实际上创建方式很多,不止上面三种,需要的时候再去查~
2.字符串比较相等
1)==比较的是对象的身份(比较两个引用中保存的地址是否相同/比较两个引用是否指向同一个对象)
例①
String str1="hello";
String str2="hello";
System.out.println(str1==str2);
结果
分析:
像"hello"这些字符串字面值常量是存在字符串常量池中,用的时候直接引用到常量池中的hello的位置就行了,保存一份即可,没必要在内存中存储两次。所以我们上面的str1和str2两个引用实际上指向的都是同一个hello对象,所以==比较对象的身份之后,结果为true。
例②
String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1==str2);
结果
分析:
上面代码中,我们使用new 关键字创建了两个对象,让str1和str2分别指向这两个对象。由于指向的是不同的对象,所以==比较之后结果为false。
由此也可以看出,直接赋值的方式创建字符串比较高效,在多次引用内容相同的字符串时,不用去搞那么多对象,字符串常量池中一个就够了。
2)equals方法比较的是两个字符串的内容
String str1=new String("hello");
String str2=new String("hello");
System.out.println(str1.equals(str2));//也可写成str2.equals(str1)
结果为true
System.out.println(str1.equals("hello"));
System.out.println("hello".equals(str1));
上面两种方式中,建议写成第二种。由于第一种中str1是引用类型的变量,空引用类型不能解引用,一旦str1是空引用,就会抛出异常,字面值常量就不会涉及到这个问题~
3.字符串常量池
池是一种重要的思想方法,把一些经常使用的对象提前创建好保存起来,以备随时去使用,降低开销,提高效率。
4.将String对象的内容添加到字符串常量池中
使用intern方法
例:
String str1=new String("hello");
System.out.println("hello"==str1);
String str2=new String("hello").intern();
System.out.println("hello"==str2);
结果
分析:
常量池是JVM划分的一个内存区域,JVM一运行的时候就会专门搞一个区域叫做常量池(也是堆的一个部分)
上面的代码中,调用intern()方法,就会拿着当前这个字符串里的内容在字符串常量池中找,看是否存在于常量池中,如果存在,则直接返回该池中的地址;如果不存在,则把当前字符串的内容添加到常量池中,返回池中的地址。
5.字符串不可变
String数组内部持有的char[] value数组的内容不能在类外部发生改变,是封装的体现。
优点:
1)方便放到池中
2)hashCode也不可变
3)线程安全更有保证
6.使用反射机制来修改String的内容
上面我们说了,字符串是不可变对象,如果我们想要改变,那重新创建一个新的就行了。
但是也有一种特殊方法去修改String的内容,使用反射机制。假如你敲我家门,我肯定不开门,但是如果是警察叔叔为了办案的话,破门而入也是合法的~
反射是面向对象程序设计的一个重要特性。
反射和封装是背道而驰的:
1)使用反射往往可能打破封装
2)反射的代码比较复杂,容易出错
3)反射牺牲了编译器自身的一些检查校验机制,更需要程序员人工保证代码的正确性。
7.字符数组,字节数组,字符串之间的相互转换
字符数组/字节数组—>字符串:上面创建字符串的第三种方式~,toString()方法
字符串—>字符数组:toCharArray
字符串—>字节数组:getBytes
例:
//字符数组/字节数组—>字符串
char[] arr1={'a','b','c'};
String str1=new String(arr1);
//字符串—>字符数组
String str2="hello";
char[] arr2=str2.toCharArray();
//字符串—>字节数组
String str3="hello";
byte[] arr3=str3.getBytes();
8.字符串比较大小
1)不忽略大小写,结果为一个数 :使用compareTo()方法
String a="Hello";
String b="hello";
System.out.println(a.compareTo(b));
结果
分析:
按照unicode比较,a>b返回大于0的数;a<0返回小于0的数;a==b返回0
在上面的代码中,大写H显然小于小写h(ASCLL码表也可以看出),所以返回的是<0的数
2)忽略大小写,结果为一个数:使用compareToIgnoreCase()方法
String a="Hello";
String b="hello";
System.out.println(a.compareToIgnoreCase(b));
结果
分析:
和上面的规则一样,只不过是忽略了大小写了,也就是大写H和小写h是一样大的,两个字符串一样大,所以返回0
3)忽略大小写,结果为布尔类型:使用equalsIgnoreCase()方法
String a="Hello";
String b="hello";
System.out.println(a.equalsIgnoreCase(b));
结果
分析:
忽略大小写后,俩字符串中的每个字符都一样大,所以返回true
9.字符串包含
使用contains()方法,结果为boolean类型
String a="Hello world java";
String b="java";
System.out.println(a.contains(b));
结果
注意:
上面的代码为例,a.contains(b)看的是a字符串中是否包含b字符串,不能写反了,那结果就不一样了。
10.子字符串起始位置下标
1)从左往右查找子字符串,如果找到返回第一次出现位置的下标:使用indexOf()方法
String a="Hello java java";
String b="java";
System.out.println(a.indexOf(b));
结果
2)从右往左查找子字符串,如果找到则返回第一次出现位置的下标:使用lastIndexOf()方法
String a="Hello java java";
String b="java";
System.out.println(a.lastIndexOf(b));
结果
11.判定字符串以XXX开头/结尾
1)判断以XXX开头:使用startWith()方法,返回结果为boolean类型
用法:在网络编程中,判断某个链接的协议类型
String a="https://www.baidu.com";
String b="https://";
System.out.println(a.startsWith(b));
结果
2)判断以XXX结尾:使用endsWith()方法,返回结果为boolean类型
用法:判定某个文件的类型
String a="a.java";
String b=".java";
System.out.println(a.endsWith(b));
结果
12.字符串替换
1)替换掉字符串中出现的所有子串:使用replaceAll()方法
String a="Hello world world";
String b="world";
System.out.println(a.replaceAll(b,"java"));
结果
2)替换掉字符串中第一次出现的子串:使用replaceFrist()方法
String a="Hello world world";
String b="world";
System.out.println(a.replaceFirst(b,"java"));
结果
13.字符串拆分
使用split()方法
例①按空格分割
String a="Hello world java";
String[] result=a.split(" "); //分割符为空格
for(String x:result){
System.out.println(x);
}
结果
例②按.分割
String a="Hello.world.java";
String[] result=a.split("\\.");
for(String x:result){
System.out.println(x);
}
结果
分析:
可以发现,在按照.分割的时候前面多了两个反斜杠\\
regex表示正则表达式,正则表达式中有很多特殊的符号,"."也是其中之一,为了解决这个问题,需要使用“正则表达式”中的转义字符,也就是正则表达式见到"."是当作特殊符号来对待的,而见到"\."才当作是.本身来看待。接下来,Java中的字符串又把\当成Java的转义字符了,为了表示一个原始的\,需要再次转义。最终为"\\."
总的来说,a.split("\\.");涉及到了两次转义,一次是Java中的转义,一次是正则表达式中的转义
14.字符串截取
使用subString()方法
1)截取一个区间[begin,end),前闭后开
String a="Hello world java";
System.out.println(a.substring(6,11));
结果
2)从某个位置开始截取(包含此位置)
String a="Hello world java";
System.out.println(a.substring(6));
结果
15.其他
1)去掉左右空白符:使用trim()方法
String a=" Hello world ";
System.out.println("["+a.trim()+"]");
结果
注意:空白符包括:空格、换行、回车、制表符、翻页符、垂直制表符...
2)
- toUpperCase() //小写字母转大写
- toLowerCase() //大写字母转小写
- intern() //字符串入池
- concat() //字符串拼接,相当于"+"
- isEmpty() //判断是否为空白字符串
16.StringBuffer和StringBuilder
StringBuffer、StringBuilder和String是不同的类。上面说了,String类型创建的变量,它所指向的内容具有不可改变性,除非使用特殊方法(反射机制)。但是为了方便修改字符串,所以就引入了StringBuffer类和StringBuilder类,也就是这两个类创建的变量所指向的内容可以修改。
①字符串末尾拼接:使用append()方法
StringBuffer str=new StringBuffer("hello");
for(int i=0;i<5;i++){
str.append(i);
}
System.out.println(str);
结果
分析:append()方法,就是直接把参数拼接到原来内存的末尾了,如果拼接的内容太多,超出内存的范围,str会自动扩容。
②字符串反转:使用reverse()方法
StringBuffer str=new StringBuffer("hello");
System.out.println(str.reverse());
结果
③删除规定下标范围的子字符串:使用delete()方法,范围是[begin,end)前闭后开
StringBuffer str=new StringBuffer("Hello,java,world");
System.out.println(str.delete(6,11));
结果
④向指定位置插入数据:使用insert()方法
StringBuffer str=new StringBuffer("Hello rld");
System.out.println(str.insert(6,"wo"));
结果
总结StringBuider和StringBuffer:
两个类的相关操作区别不大,上面是对于StringBuffer类操作的举例。
核心区别:StringBuilder 线程不安全,StringBuffer线程安全
本文地址:https://blog.csdn.net/weixin_43939602/article/details/112851312