认识 String 类
这里写目录标题
1.创建字符串
// 方式一
String str = "Hello Bit";
// 方式二 调用构造方法进行构造对象
String str2 = new String("Hello Bit");
// 方式三
char[] array = {'a', 'b', 'c'};
String str3 = new String(array);
注意事项
:
“hello” 这样的字符串字面值常量, 类型也是 String.
String 也是
引用类型
. String str = “Hello”;
2.字符串比较相等
-
String 使用 == 比较并不是在比较字符串
内容
, 而是比较两个引用是否
指向同一个对象
.
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
// 执行结果
true
str1 和 str2 是指向同一个对象的. 此时如 “hello” 这样的字符串常量是在字符串常量池中.
String str1 = "hello";
String str2 = new String("hello");
System.out.println(str1 == str2);
//执行结果
false
str2 是新建一个这样的方式创建的 String 对象相当于再堆上另外开辟了空间来存储
“hello” 的内容, 也就是内存中存在两份 “hello”
- 想比较字符串的内容, 必须采用String类提供的equals方法
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
// System.out.println(str2.equals(str1)); // 或者这样写也行
// 执行结果
true
equals 使用注意事项:
String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
上面两种方式,更推荐使用 “方式二”. 一旦 str 是 null, 方式一的代码会抛出异常, 而方式二不会。
3.字符串常量池
字符串常量池主要是存储字符串常量,本质上是一个哈希表。
是因为Java为String开辟的一块内存缓冲区,为了提高性能同时减少内存开销。在JVM中,字符串常量池由一个哈希表实现。默认容量为1009。当字符串常量池中的存储比较多的字符串时,会导致hash冲突,从而每个节点形成长长的链表,导致性能下降。所以在使用字符串常量池时,一定要控制容量。
它的主要使用方法有两种:
-
直接使用双引号声明出来的
String
对象会直接存储在常量池中。 -
如果不是用双引号声明的
String
对象,可以使用
String
提供的
intern
方法。intern 方法会从字符串常量池中查询当前字符串是否存在,若不存在就会将当前字符串放入常量池中
Java中两种创建字符串对象的方式的分析:
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
采用双引号创建一个字符串时,JVM首先会去字符串池中查找是否存在”hello”这个对象,如果不存在,则在字符串常量池中创建并存放一个”hello”对象,然后将池中”hello”这个对象的引用地址返回给”hello”对象的引用str1,这样str1会指向字符串常量池中”hello”这个字符串对象;如果存在,则不创建任何对象 ,直接将池中”hello”这个对象的地址返回,赋给引用str2。因为str1、str2都是指向同一个字符串池中的”hello”对象,所以结果为true。
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);
//执行结果
false
采用new关键字新建一个字符串时,JVM首先在字符串常量池中查找有没有”hello”这个字符串对象,如果有,则直接在在池中寻找”hello”字符串,在堆中创建一个”hello”字符串对象,然后将堆中的这个”hello”对象的地址返回赋给引用str1,这样,str1就指向了堆中创建的这个”hello”字符串对象;如果没有,则首先在字符串常量池中创建一个”hello”字符串对象,然后再在堆中创建一个”hello”字符串对象,然后将堆中这个”hello”字符串对象的地址返回赋给str1引用,这样,str1指向了堆中创建的这个”hello”字符串对象。str2则指向了堆中创建的另一个”hello”字符串对象。str1 、str2是两个指向不同对象的引用,结果当然是false。
4.理解String字符串不可变
字符串是一种不可变对象. 它的内容不可改变。
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果
hello world!!!
形如 += 这样的操作, 表面上好像是修改了字符串, 其实不是,而是创建了一个新的字符串。
5.字符, 字节与字符串
5.1 字符与字符串
字符串内部包含一个字符数组,String 可以和 char[] 相互转换.
1.将字符数组的所有内容都转换为字符串
char[] value = {'a','b','c','d','e'};
String str = new String(value);
System.out.println(str); //abcde
2.将字符数组的指定部分内容都转换为字符串
char[] value = {'a','b','c','d','e'};
String str1 = new String(value,1,4);
System.out.println(str1); //bcde
3.取得指向索引的字符,索引从0开始
String str2 = "hello";
char ch = str2.charAt(2);//获取到2下标的字符
System.out.println(ch);//l
4.将字符串变为字符数组返回
String str2 = "hello";
char[] chars = str2.toCharArray();//把str2指向的字符串对象,变成字符数组
System.out.println(Arrays.toString(chars));//[h, e, l, l, o]
5.2 字节与字符串
字节常用于数据传输以及编码转换的处理之中,String 也能方便的和 byte[] 相互转换
1.将字节数组变为字符串
byte[] bytes = {97,98,99,100};
String str = new String(bytes);
System.out.println(str); //abcd
2.将指定部分字节数组的内容变为字符串
byte[] bytes = {97,98,99,100};
String str = new String(bytes,1,3);//从下标为1开始,长度为3
System.out.println(str); //bcd
3.将字符串以字符数组的形式返回
String str2 = "张杰";
byte[] bytes1 = str2.getBytes(StandardCharsets.UTF_8);
System.out.println(Arrays.toString(bytes1));//[-27, -68, -96, -26, -99, -80]
4.编码转换处理
public static void main(String[] args) throws UnsupportedEncodingException {
String str2 = "张杰";
byte[] bytes1 = str2.getBytes("GBK");
System.out.println(Arrays.toString(bytes1));[-43, -59, -67, -36]
}
那么何时使用 byte[], 何时使用 char[] 呢?
byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
针对二进制数据来操作.
char[] 是把String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
6. 字符串常见操作
6.1 字符串比较
1.区分大小写的比较
String str1 = "abc";
String str2 = "Abc";
System.out.println(str1.equals(str2));// false
2.不区分大小写的比较
String str1 = "abc";
String str2 = "Abc";
System.out.println(str1.equalsIgnoreCase(str2));// true
3.比较两个字符串大小关系
String str1 = "abc";
String str2 = "Abc";
int ret = str1.compareTo(str2);
System.out.println(ret);
在String类中compareTo()方法是一个非常重要的方法,该方法返回一个
整型
,该数据会根据大小关系返回三类内容:
- 相等:返回0.
- 小于:返回内容小于0.
- 大于:返回内容大于0
6.2 字符串查找
1.判断一个字符串是否存在
String str = "abcdef";
String tmp = "abc";
Boolean flg = str.contains(tmp);//true
System.out.println(flg);
2.从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1
3.从指定位置开始查找子字符串位置
String str = "ababcabcd";
String tmp = "abc";
int index = str.indexOf(tmp);//从头开始找 //类似于C的strstr-> KMP算法
System.out.println(index);//2
int index = str.indexOf(tmp,3);//从下标为3的位置开始找
System.out.println(index);//5
4.从后向前查找子字符串位置
5.从指定位置由后向前查找子字符串位置
String str = "ababcabcd";
String tmp = "abc";
System.out.println(str.lastIndexOf(tmp));//5
System.out.println(str.lastIndexOf(tmp,4));//2 //指定位置为下标为4的位置
6.判断是否以指定字符串开头
7.从指定位置开始判断是否以指定字符串开头
String str = "ababcabcd";
String tmp = "abc";
System.out.println(str.startsWith(tmp));//false
System.out.println(str.startsWith(tmp,2));//true
8.判断是否以指定字符串结尾
String str = "ababcabcd";
String tmp = "abc";
System.out.println(str.endsWith("cde"));//false
6.3 字符串替换
String str = "ababcabcdabcde";
//替换所有的指定内容 public String replaceAll(String regex,String replacement)
String ret = str.replaceAll("ab","mm");//mmmmcmmcdmmcde
//替换首个内容public String replaceFirst(String regex,String replacement)
String ret1 = str.replaceFirst("ab","pp");//ppabcabcdabcde
6.4 字符串拆分
将字符串全部拆分 public String[] split(String regex)
将字符串部分拆分,该数组长度是limit极限 public String[] split(String regex,int limit)
代码实例:1.实现字符串的拆分处理
String str = "hello world hello bit" ;
String[] result = str.split(" ") ; // 按照空格拆分
for(String s: result) {
System.out.println(s);
//hello
//world
//hello
//bit
}
代码示例: 2.字符串的部分拆分
代码示例: 3.拆分IP地址
String str = "192.168.1.1";
String[] strings = str.split("\\.",3);//最多分成3段
for (String s:strings){
System.out.println(s);
}
//192
//168
//1.1
代码实例:4.多次拆分
String str = "name=zhangsan&age=19";
String[] strings = str.split("&");
for (String s:strings){
String[] ss = s.split("=");//ss:name zhangsan
//System.out.println(s);
//s: name=zhangsan 下次:s : age=19
for (String tmp:ss) {
System.out.println(tmp);//name zhangsan age 19
}
}
注意事项:
1.字符”|“,”*“,”+“, “.” 都得加上转义字符,前面加上”\\”.
2.而如果是”\\“,那么就得写成”\\\\”.
String str2 = "192\\168\\1\\1";
String[] strings1 = str2.split("\\\\",7);
for (String s:strings1) {
System.out.println(s);
}
3.如果一个字符串中有多个分隔符,可以用”|”作为连字符
String str = "Java30 12&21#hello";
String[] strings = str.split(" |&|#");
for (String s:strings) {
System.out.println(s);
}
6.5 字符串截取
1.从指定索引截取到结尾 public String substring(int beginIndex)
String str = "abcdefgh";
String sub = str.substring(2);
System.out.println(sub); //cdefgh
2.截取部分内容 public String substring(int beginIndex,int endIndex)
String str = "abcdefgh";
String sub = str.substring(2,4);
System.out.println(sub); //cd
注意事项:
- 索引从0开始
-
注意
前闭后开
区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
6.6 其他操作方法
1.去掉字符串的左右空格,保留中间空格 ——trim()方法
String str = " abc defg ";
String sub = str.trim();
System.out.println(sub);
2.字符串转大写、小写——toUpperCase() 、toLowerCase()
String str = "abcdefBFRG123高";
String ret = str.toUpperCase();//ABCDEFBFRG123高
String ret1 = str.toLowerCase();//abcdefbfrg123高
3.字符串入池 public native String intern()
4.拼接——concat()
5.取得字符串长度——length()
6.判断是否为空字符串,但不是null,是长度为0—— isEmpty()
String str = "jinzh";
String ret = str.concat("zh");//拼接
System.out.println(ret);//jinzhzh 拼接后的不入常量池
System.out.println(str.length());//字符串长度为5
System.out.println(str.isEmpty());//false
7. StringBuffer 和 StringBuilder
任何的字符串常量都是String对象,而且String的常量一旦声明就不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和
StringBuilder类。
StringBuilder sb = new StringBuilder();
sb.append("as").append("5");
System.out.println(sb);
用StringBuffer和StringBuilder类的好处:
//String str = "abcdef";
StringBuilder sb = new StringBuilder();
sb.append("abcdef");
//str += "123";//str = str + "123" //用String很浪费空间
sb.append("123"); //用StringBuilder依然是在原来的对象基础之上拼接,最后返回的还是原来的地址,这样不会浪费空间
//str = sb.toString();
System.out.println(sb);
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
a). String变为StringBuffer:利用StringBuffer的构造方法或append()方法
String str = "abcdef";
StringBuffer sb = new StringBuffer();
sb.append("sji");
return sb;
b). StringBuffer变为String:调用toString()方法
StringBuilder sb = new StringBuilder();
return sb.toString();
除了append()方法外,StringBuffer也有一些String类没有的方法:
1.字符串反转:
public synchronized StringBuffer reverse()
StringBuilder sb = new StringBuilder("abcdef");
System.out.println(sb.reverse());//fedcba
2.删除指定范围的数据:
public synchronized StringBuffer delete(int start, int end)
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 9));//hellod 区间是左闭右开
3.插入数据
public synchronized StringBuffer insert(int offset, 各种数据类型 b)
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 10).insert(0, "你好"));//你好hello
如果在循环里面,进行字符串的拼接。尽量不要使用String,优先使用StringBuffer和StringBuilder。
请解释String、StringBuffer、StringBuilder的区别:
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
StringBuffer与StringBuilder大部分功能是相似的
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作