String类
文章目录
- String类
- 1. 创建字符串
- 2. 字符串比较相等
- 3. 字符串常量池
- 4. 字符串不可变
- 5. 字符,字节,字符串
- 5.1 字符与字符串
- 5.2 字节与字符串
- 5.3 小结
- 6. 字符串常见操作
- 6.1 字符串比较
- 6.2 字符串查找
- 6.3 字符串替换
- 6.4 字符串拆分
- 6.5 字符串截取
- 6.6 其他操作方法
- 7. StringBuffer 和 StringBulider
1. 创建字符串
常见的构造String的方式
//方式一
String str = "hello";
//方式二
String str2 = new String("hello");
//方式三
char [] array = {'a','b','c'};
Strin str3 = new String(array);
注意事项
- "hello"这样的字符串字面常量,类型也是String
- String是引用类型,String str = “hello”; 这样的代码内存布局如下
str1 = "world";
System.out.println(str2);
//执行结果
hello
修改str1之后,str2没有发生变化,实际上,str1 = “wordl” 是将str1这个引用指向了一个新的对象
2. 字符串比较相等
两个int型变量,判断其相等可以使用==完成
int x = 10;
int y = 10;
System.out.println(x==y);
//执行结果
true
String类对象上使用== ?代码1:
String str1 = "hello";
String str2 = "hello";
System.out.println(str1 == str2);
//执行结果
true
代码2:
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1 == str2);
//执行结果
false
分析两种创建String方式的差异
代码1:
str1 和 str2 是指向同一个对象的,此时像"hello" 这样的字符串常量实在字符串常量池中
字符串常量池:如 “Hello” 这样的字符串字面值常量, 也是需要一定的内存空间来存储的. 这样的常量具有一个特点, 就是不需要修改(常量). 所以如果代码中有多个地方引用都需要使用 “Hello” 的话, 就直接引用到常量池的这个位置就行了, 而没必要把 “Hello” 在内存中存储两次.
代码2:
通过 String str1 = new String(“Hello”); 这样的方式创建的 String 对象相当于再堆上另外开辟了空间来存储"Hello" 的内容, 也就是内存中存在两份 “Hello”
String 使用 == 比较并不是在比较字符串内容, 而是比较两个引用是否是指向同一个对象
Java 中要想比较字符串的内容, 必须采用String类提供的equals方法
String str1 = new String("Hello");
String str2 = new String("Hello");
System.out.println(str1.equals(str2));
//执行结果
true
equals使用注意事项
String str = new String("Hello");
// 方式一
System.out.println(str.equals("Hello"));
// 方式二
System.out.println("Hello".equals(str));
str如果是null,那方式一的代码会抛异常,方式二不会
注意事项: “Hello” 这样的字面值常量, 本质上也是一个 String 对象, 完全可以使用 equals 等 String 对象的方法.
3. 字符串常量池
- 直接赋值
String str1 = "hello" ;//存入字符串常量池,
String str2 = "hello" ;//检查字符串常量池中是否有hello,如果有就直接引用这个hello
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true
如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中.如果下次继续使用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用
- 采用构造方法
String str = new String("hello");
这样会在堆上开辟新的内存空间,不会进入字符串常量池
我们可以使用 String 的 intern 方法来手动把 String 对象加入到字符串常量池中
// 该字符串常量并没有保存在字符串常量池之中
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果
false
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2);
// 执行结果
true
String类中两种对象实例化的区别
- 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
- 构造方法:会开辟两块堆内存空间,不会自动保存在对象池中,可以使用intern()方法手工入池。
4. 字符串不可变
字符串是一种不可变对象. 它的内容不可改变.
String 类的内部实现也是基于 char[] 来实现的, 但是 String 类并没有提供 set 方法之类的来修改内部的字符数组.
String str = "hello" ;
str = str + " world" ;
str += "!!!" ;
System.out.println(str);
// 执行结果
hello world!!!
形如 += 这样的操作, 表面上好像是修改了字符串,实际上并不是String对象本身发生了改变,而是str引用指向了其他的对象
5. 字符,字节,字符串
5.1 字符与字符串
字符串内部包含一个字符数组,String 可以和 char[] 相互转换.
方法名称 | 类型 | 描述 |
public String(char vlaue[]) | 构造 | 将字符数组中的所有内容变为字符串 |
public String(char value[],int offset,int count) | 构造 | 将部分字符数组中的内容变为字符串 |
public char charAt(int index) | 普通 | 取得指定索引位置的字符,索引从0开始计算 |
public char[] toCharArray() | 普通 | 将字符串变为字符数组返回 |
代码示例:
public static void main(String[] args) {
char [] val = {'a','b','c','d','e'};//将字符数组转成字符串
String str = new String(val);
System.out.println(str);
String str1 = new String(val,1,3);//偏移量从0开始记,
System.out.println(str1);//这里是把偏移量1到3的字符转成字符串
System.out.println("==========================");
String str2 = "hello";
char ch = str2.charAt(1);//获取字符串1下标的字符
System.out.println(ch); //打印e
char [] chars = str2.toCharArray();//把str2指向的字符串对象 ,转成字符数组
System.out.println(Arrays.toString(chars));
}
//执行结果
abcde
bcd
==========================
e
[h, e, l, l, o]
给定字符串一个字符串, 判断其是否全部由数字所组成
public static void main(String[] args) {
String str = "123456798";
System.out.println(isNumber(str)?"字符串由数字组成":"字符串有非数字成员");
}
public static boolean isNumber(String str){
char[] data = str.toCharArray();
for (int i = 0; i < data.length; i++) {
if(data[i] < '0' || data[i] > '9'){
return false;
}
}
return true;
}
//执行结果
字符串由数字组成
5.2 字节与字符串
字节常用于数据传输以及编码转换的处理之中,String 也能方便的和 byte[] 相互转换
方法名称 | 类型 | 描述 |
public String(byte bytes[]) | 构造 | 将字节数组转成字符串 |
public String(byte bytes[],int offset,int length) | 构造 | 将部分字节数组中的内容转成字符串 |
public byte[] getBytes() | 普通 | 将字符串以字节数组的形式返回 |
代码示例:实现字符串与字节数组的转换
public static void main(String[] args) {
String str = "helloworld";
byte [] bytes = str.getBytes();
for (int i = 0; i < bytes.length; i++) {
System.out.print(bytes[i]+ " ");
}
System.out.println();
System.out.println(new String(bytes));
}
//执行结果
104 101 108 108 111 119 111 114 108 100
helloworld
5.3 小结
- byte[] 是把 String 按照一个字节一个字节的方式处理, 这种适合在网络传输, 数据存储这样的场景下使用. 更适合
针对二进制数据来操作. - char[] 是吧 String 按照一个字符一个字符的方式处理, 更适合针对文本数据来操作, 尤其是包含中文的时候
6. 字符串常见操作
6.1 字符串比较
方法名称 | 类型 | 描述 |
public boolean equal(Object anObject) | 普通 | 区分大小写的比较 |
public boolean equalsIgnoreCase(String anotherString) | 普通 | 不区分大小写的比较 |
public int compareTo(String anotherString) | 普通 | 比较两个字符串大小关系 |
代码示例
public static void main(String[] args) {
String str = "hello";
String str1 = "Hello";
System.out.println(str.equals(str1));
System.out.println(str.equalsIgnoreCase(str1));
}
//执行结果
false
true
在String类中compareTo()方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内容:
- 相等:返回0.
- 小于:返回内容小于0.
- 大于:返回内容大于0。
System.out.println("A".compareTo("a")); // -32
System.out.println("a".compareTo("A")); // 32
System.out.println("A".compareTo("A")); // 0
System.out.println("AB".compareTo("AC")); // -1
System.out.println("刘".compareTo("杨"));
compareTo()是一个可以区分大小关系的方法,是String方法里是一个非常重要的方法。
字符串的比较大小规则, 总结成三个字 “字典序” 相当于判定两个字符串在一本词典的前面还是后面. 先比较第一个字符的大小(根据 unicode 的值来判定), 如果不分胜负, 就依次比较后面的内容
6.2 字符串查找
方法名称 | 类型 | 描述 |
public boolean contains(CharSequence s) | 普通 | 判断一个子字符串是否存在 |
public int indexOf(String str) | 普通 | 从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1 |
public int indexOf(String str,int fromIndex) | 普通 | 从指定位置开始查找子字符串位置 |
public int lastIndexOf(String str) | 普通 | 从后向前查找子字符串的位置 |
public int lastIndexOf(String str,int fromIndex) | 普通 | 从指定位置从后向前查找 |
public boolean startsWith(String prefix) | 普通 | 判断是否以指定字符串开头 |
public boolean startsWith(String prefix,int toffset) | 普通 | 从指定位置开始判断是否以指定字符串开头 |
public boolean endsWith(String suffix) | 普通 | 判断是否以指定字符串结尾 |
代码示例
public static void main(String[] args) {
String str = "helloworld";
String str1 = "world";
System.out.println(str.contains(str1));//判断字符串str1在str中是否存在
System.out.println(str.indexOf(str1));
//从头开始找str1的位置,找到返回str1开始的索引 5
System.out.println(str.indexOf(str1,6));//从6位置开始找world 找不到
System.out.println(str.lastIndexOf(str1));//从后向前找
System.out.println(str.lastIndexOf(str1,3));//从倒数第三个位置开始找,找不到
System.out.println(str.startsWith(str1));//判断是否以str1字符串开头
System.out.println(str.startsWith(str1,5));
//从偏移量为5的位置开始,判断是否以str1字符串开头
System.out.println(str.endsWith(str1));//判断是否以str1字符串结尾
}
6.3 字符串替换
方法名称 | 类型 | 描述 |
public String replaceAll(String regex,String replacement) | 普通 | 替换所有的指定内容 |
public String replaceFirst(String regex,String replacement) | 普通 | 替换首个内容 |
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.replaceAll("l","o"));//将所有的l替换成o
System.out.println(str.replaceFirst("l","o"));//将第一个l替换成o
}
//执行结果
heoooworod
heoloworld
注意事项:由于字符串是不可变对象,替换不修改当前字符串,而是产生一个新的字符串
6.4 字符串拆分
可以将一个完整的字符串按照指定的分隔符划分为若干个子字符串
方法名称 | 类型 | 描述 |
public String [] split(String regex) | 普通 | 将字符串完全拆分 |
public String [] split(String regex,int limit) | 普通 | 将字符串拆分,该数组长度就是limit极限 |
代码示例:实现字符串的拆分处理
public static void main(String[] args) {
String str = "he llo wo rl d";
String [] s = str.split(" ");//按空格拆分 定义一个String类型的数组s接收拆分出来的字符串
for (String s1:s) { //遍历s数组,打印出里面的字符串
System.out.println(s1);
}
}
//执行结果
he
llo
wo
rl
d
代码示例:字符串的部分拆分
public static void main(String[] args) {
String str = "hello world hello java";
String [] s = str.split(" ",2);//按空格拆分,最多拆成2个,不是平均拆分
for (String s1:s) {
System.out.println(s1);
}
}
//执行结果
hello
world hello java
注意事项:有些特殊字符作为分隔符可能无法正确切分,需要加上转义
代码示例:拆分IP地址
public static void main(String[] args) {
String str = "192.168.1.1" ;
String[] result = str.split("\\.") ;
for(String s: result) {
System.out.println(s);
}
}
//执行结果
192
168
1
1
注意事项:
- 字符"|“,”*“,”+“都得加上转义字符,前面加上”\".
- 而如果是"“,那么就得写成”\\".
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符
代码示例:多次拆分
public static void main(String[] args) {
String str = "name=zhangsan&age=18" ;
String[] result = str.split("&") ;
for (int i = 0; i < result.length; i++) {
String[] temp = result[i].split("=") ;
for (String s:temp) {
System.out.println(s);
}
}
}
//执行结果
name
zhangsan
age
18
6.5 字符串截取
从一个完整的字符串之中截取出部分内容。可用方法如下:
方法名称 | 普通 | 描述 |
public String substring(int beginIndex) | 普通 | 从指定索引截取到结尾 |
public String substring(int beginIndex,int endIndex) | 普通 | 截取部分内容 |
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.substring(5));//从偏移量为5的位置截取到结尾
System.out.println(str.substring(2,5));//从偏移量为2的位置开始截取到偏移量为5的位置
}
注意事项
- 索引从0开始
- 注意前闭后开区间的写法, substring(2, 5) 表示包含 2 号下标的字符, 不包含 5 号下标
6.6 其他操作方法
方法名称 | 类型 | 描述 |
public String trim() | 普通 | 去掉字符串中的左右空格,保留中间的空格 |
public String toUpperCase() | 普通 | 字符串转大写 |
public String toLowerCase() | 普通 | 字符串转小写 |
public native String intern() | 普通 | 字符串入池操作 |
public String concat(String str) | 普通 | 字符串连接,相当于"+",拼接后的字符串不入池 |
public int length() | 普通 | 取得字符串的长度 |
public boolean isEmpty() | 普通 | 判断是否为空字符串,不是null,而是长度为0 |
代码示例:trim()
public static void main(String[] args) {
String str = " hello world ";
System.out.println(str.trim());
String s = " hello world ";
System.out.println("[" + s + "]");
System.out.println(s.trim());
}
//执行结果
hello world
[ hello world ]
hello world
代码示例:大小写转换,字符串连接
public static void main(String[] args) {
String str = "abc";
System.out.println(str.toUpperCase());
String s = "ABC";
System.out.println(s.toLowerCase());
System.out.println(str.concat(s));
}
//执行结果
ABC
abc
abcABC
代码示例:length() ,isEmpty()
public static void main(String[] args) {
String str = "hello hhhh 哈哈";
System.out.println(str.length());
System.out.println(str.isEmpty());
System.out.println("".isEmpty());
System.out.println(new String().isEmpty());
}
//执行结果
13
false
true
true
7. StringBuffer 和 StringBulider
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。
通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。
StringBuffer 和 StringBuilder 大部分功能是相同的,
在String中使用"+"来进行字符串连接,但是这个操作在StringBuffer类中需要更改为append()方法:
public class Test{
public static void main(String[] args) {
StringBuffer sb = new StringBuffer();
sb.append("Hello").append("World");
fun(sb);
System.out.println(sb);
}
public static void fun(StringBuffer temp) {
temp.append("\n").append("HelloJava");
}
}
String和StringBuffer最大的区别在于:String的内容无法修改,而StringBuffer的内容可以修改。频繁修改字符串的情况考虑使用StingBuffer
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
String变为StringBuffer:利用StringBuffer的构造方法或append()方法
StringBuffer变为String:调用toString()方法。
除了append()方法外,StringBuffer也有一些String类没有的方法:
- 字符串反转
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.reverse());
//执行结果
dlrowolleh
- 删除指定范围的数据
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 10));
//执行结果
hello
- 插入数据
StringBuffer sb = new StringBuffer("helloworld");
System.out.println(sb.delete(5, 10).insert(0, "你好"));
//执行结果
你好hello
String、StringBuffer、StringBuilder的区别
- String的内容不可修改,StringBuffer与StringBuilder的内容可以修改.
- StringBuffer与StringBuilder大部分功能是相似的
- StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作