本篇博客将详细讲解java中的String类。
文章目录
创建字符串
常见的构造String的方式
//方式一
String str = "hello";
//方式二
String str1 = new String("Hello");
//方式三
char[] array = {'a', 'b', 'c'};
String str2 = new String(array);
注意:
- "hello"这样的字符串字面值常量,类型也是String。
- String也是引用类型。
我们来看下面这段代码:
public class TestDemo {
public static void func(String s, char[] array) {
s = "abc";
array[0] = 'x';
}
public static void main(String[] args) {
String str = "aaa";
char[] chars = {'b','b','c','c'};
func(str, chars);
System.out.println(str);
System.out.println(Arrays.toString(chars));
}
}
这段代码的结果为:
为什么会出现这样的结果呢?我们来看看这段代码的内存图。
所以才会上述的结果。
常量池
常量池一般有三类:Class文件常量池、运行时常量池和字符串常量池。
Class文件常量池:用于存放编译器生成的各种字面量和符号引用。
运行时常量池:当程序把编译好的字节码文件,加载到JVM当中后会生成一个运行时常量池。运行时常量池是存放在方法区当中的。
字符串常量池:主要存放字符串常量,本质上是一个哈希表。
字符串比较
在Java中,比较两个字符串是否相等,一般使用String类提供的equals方法。例如:
String str1 = new String("hello");
String str2 = new String("hello");
System.out.println(str1.equals(str2));
执行结果为:
注意:
如果出现下面这样的代码,那么就会报错:
String str1 = null;
String str2 = new String("hello");
System.out.println(str1.equals(str2));
执行结果为:
理解字符串不可变
我们先来看这样一段代码:
String str = "hello";
str = str + " world";
str += "!!!";
System.out.println(str);
执行结果为:
这段代码,表明上好像是修改了字符串,但实际上并不是,而是创建了五个变量:
如果实在是想修改字符串,可以这样做:
String str = "hello";
str = "a" + str.substring(1);
System.out.println(str);
执行结果为:
当然,也可以使用反射的方法去修改:
String str = "hello";
// 获取 String 类中的 value 字段. 这个 value 和 String 源码中的 value 是匹配的.
Field valueField = String.class.getDeclaredField("value");
// 将这个字段的访问属性设为 true
valueField.setAccessible(true);
// 把 str 中的 value 属性获取到.
char[] value = (char[]) valueField.get(str);
// 修改 value 的值
value[0] = 'a';
System.out.println(str);
执行结果为:
为什么 String 要不可变?
方便实现字符串对象池。如果 String 可变,那么对象池就需要考虑何时深拷贝字符串的问题了。
不可变对象是线程安全的。
不可变对象更方便缓存 hash code,作为 key 时可以更高效的保存到 HashMap 中。
字符、字节与字符串
字符与字符串
字符串内部包含一个字符数组,String可以和char[]相互转换。
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String(char value[]) | 构造 | 将字符数组中所有内容变为字符串 |
2 | public String (char value[], int offset, int count) | 构造 | 将部分字符数组中的内容变为字符串 |
3 | publilc char charAt(int index) | 普通 | 取得指定索引位置的字符,索引从0开始 |
4 | public char[] toCharArray() | 普通 | 将字符串变为字符数组返回 |
代码示例:
将字符合并为字符串
char[] value = {'a','b','c','d','e'};
String str = new String(value);
System.out.println(str);
执行结果为:
获取字符串中的某个字符
String str = "abcdef";
char val = str.charAt(3);
System.out.println(val);
执行结果为:
将字符数组中部分字符合并成字符串
char[] value = {'a','b','c','d','e'};
String str = new String(value,1,3);
System.out.println(str);
执行结果为:
将字符串转换为字符
String str = "abcdef";
char[] chars = str.toCharArray();
System.out.println(Arrays.toString(chars));
执行结果为:
判断字符串是否由数字构成
public static void main(String[] args) {
String str = "123a456";
System.out.println(isNumber(str));
}
public static boolean isNumber(String s) {
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c < '0' || c > '9') {
return false;
}
}
return true;
}
执行结果为:
字节与字符串
字节常用于数据传输以及编码转换的处理之中,String也能方便的和byte[]相互转换。
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String(byte bytes[]) | 构造 | 将字节数组变为字符数组 |
2 | public String(byte bytes[], int offset, int length) | 构造 | 将部分字节数组中的内容变为字符串 |
3 | public byte[] getBytes() | 普通 | 将字符串以字节数组的形式返回 |
4 | public byte[] getBytes(String charsetName)throws UnsupportedEncodingException | 普通 | 编码转换处理 |
代码示例:
实现字符串与字节数组的转换
byte[] bytes = {97,98,99,100,101,102};
String str = new String(bytes);
System.out.println(str);
System.out.println("========================");
String str2 = "abcdefg";
byte[] bytes1 = str2.getBytes();
System.out.println(Arrays.toString(bytes1));
执行结果为:
编码转换处理
String str2 = "你好";
byte[] bytes1 = str2.getBytes("utf-8");
System.out.println(Arrays.toString(bytes1));
执行结果为:
小结
byte[] 是把 String 按照一个字节一个字节的方式处理,这种适合在网络传输,数据存储这样的场景下使用,更适合针对二进制数据来操作。
char[] 是把 String 按照一个字符一个字符的方式处理,更适合针对文本数据来操作,尤其是包含中文的时候。
字符串常见操作
字符串比较
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean equals(Object anObject) | 普通 | 区分大小写的比较 |
2 | public boolean equalsIgnoreCase(String anotherString) | 普通 | 不区分大小写的比较 |
3 | public int compareTo(String anotherString) | 普通 | 比较两个字符串大小关系 |
代码示例:
String str1 = "hello";
String str2 = "HELLO";
System.out.println(str1.equals(str2));
System.out.println(str1.equalsIgnoreCase(str2));
System.out.println(str1.compareTo(str2));
运行结果为:
在String类中compareTo()方法是一个非常重要的方法,该方法返回一个整型,该数据会根据大小关系返回三类内容:
- 相等:返回0
- 小于:返回内容小于0
- 大于:返回内容大于0
字符串查找
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public boolean contains(CharSequence s) | 普通 | 判断一个子字符串是否存在 |
2 | public int indexOf(String str) | 普通 | 从头开始查找指定字符串的位置,查到了返回位置的开始索引,如果查不到返回-1 |
3 | public int indexOf(String str, int fromIndex) | 普通 | 从指定位置开始查找子字符串位置 |
4 | public int lastIndexOf(String str) | 普通 | 由后向前查找子字符串位置 |
5 | public int lastIndexOf(String str, int fromIndex) | 普通 | 从指定位置由后向前查找 |
6 | public boolean startsWith(String prefix) | 普通 | 判断是否以指定字符串开头 |
7 | public boolean startsWith(String prefix, int toffset) | 普通 | 从指定位置开始判断是否以指定字符串开头 |
8 | public boolean endsWith(String suffix) | 普通 | 判断是否以指定字符串结尾 |
代码示例:
String str1 = "abcdefabcdef";
String str2 = "bcd";
System.out.println(str1.contains(str2));
System.out.println(str1.indexOf(str2,3));
System.out.println(str1.lastIndexOf(str2));
System.out.println(str1.startsWith("abba"));
System.out.println(str1.endsWith("ef"));
执行结果为:
字符串替换
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String replaceAll(String regex, String replacement) | 普通 | 替换所有的指定内容 |
2 | public String replaceFirst(String regex, String replacement) | 普通 | 替换首个内容 |
代码示例:
String str1 = "abcabcabcddee";
System.out.println(str1.replace('a','x'));
System.out.println(str1.replace("ab","xy"));
System.out.println(str1.replaceAll("abc","y"));
System.out.println(str1.replaceFirst("abc","pppp"));
执行结果为:
字符串拆分
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String[] split(String regex) | 普通 | 将字符串全部拆分 |
2 | public String[] split(String regex, int limit) | 普通 | 将字符串部分拆分,该数组长度就是limit极限 |
代码示例:
String str = "name=zhangsan&age=19";
String[] strings = str.split("&");
for (String s:strings) {
System.out.println(s);
}
System.out.println("=================================");
for (String s:strings) {
String[] ss = s.split("=");
for (String tmp:ss) {
System.out.println(tmp);
}
}
执行结果为:
注意事项:
- 字符"|","*","+"都得加上转义字符,前面加上“\\”。
- 如果是"\",那么就得写成"\\"。
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符。
例如:
String str = "192.68.1.1";
String[] strings = str.split("\\.");
for (String s:strings) {
System.out.println(s);
}
System.out.println("==========================");
String str1 = "192.68.1.1";
String[] strings1 = str1.split("\\.",3);
for (String s:strings1) {
System.out.println(s);
}
System.out.println("++++++++++++++++++++++++++");
String string = "java30 12&21#hello";
String[] strings2 = string.split(" |&|#");
for (String s:strings2) {
System.out.println(s);
}
执行结果为:
字符串截取
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String substring(int beginIndex) | 普通 | 从指定索引截取到结尾 |
2 | public String substring(int beginIndex, int endIndex) | 普通 | 截取部分内容 |
注意事项:
- 索引从0开始。
- 注意前闭后开区间的写法,substring(0,5)表示包含0号下标的字符,不包含5号下标的字符。
代码示例:
String str = "abcdefg";
System.out.println(str.substring(5));
System.out.println(str.substring(2,6));
执行结果为:
其他操作方法
No | 方法名称 | 类型 | 描述 |
---|---|---|---|
1 | public String trim() | 普通 | 去掉字符串中的左右空格,保留中间空格 |
2 | public String toUpperCase() | 普通 | 字符串转大写 |
3 | public String toLowerCase() | 普通 | 字符串转小写 |
4 | public native String intern() | 普通 | 字符串入池操作 |
5 | public String concat(String str) | 普通 | 字符串连接,等同于“+”,拼接之后的对象不入池 |
6 | public int length() | 普通 | 取得字符串长度 |
7 | public boolean isEmpty() | 普通 | 判断是否为空字符串,但不是null,而是长度为0 |
StringBuffer和StringBuilder
首先来回顾下String类的特点:
任何的字符串常量都是String对象,而且String的常量一旦声明不可改变,如果改变对象内容,改变的是其引用的指向而已。通常来讲String的操作比较简单,但是由于String的不可更改特性,为了方便字符串的修改,提供StringBuffer和StringBuilder类。StringBuffer 和 StringBuilder 大部分功能是相同的,在String中使用"+"来进行字符串连接,但是这个操作在StringBuilder类中需要更改为append()方法。
我们先来看一下StringBuilder,
sb.append("abcdef");
sb.append("123");
System.out.println(sb);
System.out.println("========================");
System.out.println(sb.reverse());
运行结果为:
注意:String和StringBuffer类不能直接转换。如果要想互相转换,可以采用如下原则:
-
String变为StringBuffer:利用StringBuffer的构造方法或append()方法。
-
StringBuffer变为String:调用toString()方法。
例如:
public static StringBuilder func() {
String str = "abcd";
return new StringBuilder(str);
}
public static String fun() {
StringBuilder sb = new StringBuilder();
return sb.toString();
}
String、StringBuffer、StringBuilder的区别:
-
String的内容不可修改,StringBuffer与StringBuilder的内容可以修改。
-
StringBuffer与StringBuilder大部分功能是相似的。
-
StringBuffer采用同步处理,属于线程安全操作;而StringBuilder未采用同步处理,属于线程不安全操作。
结尾
本篇博客到此结束。
上一篇博客:Java学习苦旅(十三)——多态
下一篇博客:Java学习苦旅(十五)——异常