1. 什么是String类
相信大家对于"字符串"这三个字都已经耳熟能详了吧.
我们知道, 在C语言中, 是没有字符串这个类型的, 想要表示字符串的话, 就得使用字符数组对其进行表示. 不知道在大家眼里是怎样的, 但是在我看来, 这是一件个非常麻烦的事情.
好在java中有一个String类, 使用这个类来表示字符串这个类型.
2. 创建字符串
2.1 创建字符串的三种常用方法:
- 直接赋值
String str = "hello";
- 调用带有一个String参数的构造方法
String str = new String("hello");
- 通过字符数组来创建一个字符串(调用带有数组的构造方法)
char[] val = {'a', 'b', 'c'};
String str = new String(val);
2. 2 创建字符串在内存中的布局
2.2.1 字符串常量池
这里引入一个概念: 字符串常量池
像"hello"这样的字符串称为字符串字面值常量, 它的特点是不需要修改. 因此, 将它放入字符串常量池中, 每次需要使用这个字符串时, 直接到字符串常量池中调用这个字符串即可.
注意:
- 从JDK 1.7开始, 字符串常量池就被挪到了堆当中
- 相同的字符串在字符串常量池中只会被存储一次(不重复的)
- 如果存储一个字符串, 字符串常量池中没有该字符串, 就需要重新在字符串常量池中开辟一块空间存放这个字符串.
2.2.2 内存中的布局
例如:
String str = "hello";
String ret = "hello";
String tmp = "world";
由于在字符串常量池中, 相同的字符串只会被存储一次, 之后再调用这个字符串, 直接从字符串常量池中调就可以. 所以, str 和 ret 中存放的地址是相同的.
3. String使用 == 进行比较
在面向对象语言中, 凡是涉及到对象的比较, 都有三种方式: 1. 比较身份(地址). 2. 比较值. 3. 比较类型.
但是在Java中, ==是用来比较身份(地址)的.
例如:
String str = "hello";
String tmp = new String("hello");
System.out.println(str == tmp); // false
由此可见, str 里面存放的地址和 tmp 里面存放的地址是不同的.
例如:
String str = "hello";
String str1 = "hel" + "lo"; // 常量在编译的时候就是确定好的
String tmp = new String("hel") + "lo";
4. 理解字符串的不可变
字符串是一个不可变对象, 它的内容是不可变的.
public static void func(String str1, char[] ch) {
str1 = "abcdef";
ch[0] = 'g';
}
public static void main(String[] args) {
String str = "hello";
char[] chars = {'a', 'b', 'c'};
System.out.println(str); // hello
System.out.println(Arrays.toString(chars)); // abc
func(str, chars);
System.out.println(str); // hello
System.out.println(Arrays.toString(chars)); // gbc
}
由此可见, 直接修改字符串的内容, 只会修改字符串的指向而已, 字符串的内容并没有发生修改.
5. 字符, 字节与字符串
5.1 字符与字符串
字符串中是包含一个字符数组的.
例如: 给定一个字符串, 判断这个字符串全部是由数字组成的
public static boolean func(String str) {
for (int i = 0; i < str.length(); i++) {
char ch = str.charAt(i);
if(ch < '0' || ch > '9') {
return false;
}
}
return true;
}
public static void main(String[] args) {
String str = "12345a78";
System.out.println(func(str));
}
5.2 字节与字符串
5.3 char[ ] 和 byte[ ] 的 使用场景
- byte[ ] 是将String按照字节的方式进行处理的, 适合视频, 音频, 网络传输和数据存储这些场景下使用
- char[ ] 是将String按照字符的方式进行处理的, 更加适合用来处理文本数据.
6. 字符串的常见操作
6.1 字符串的比较
我们知道, 如果字符串之间用 == 进行比较的话, 比较的是地址, 并不是字符串的内容
那么要进行字符串内容的比较, 就需要使用 equals 方法
// 字符串区分大小写的比较: equals
public static void main(String[] args) {
String str1 = "hello";
String str2 = "Hello";
String str3 = "hello";
System.out.println(str1.equals(str2)); // false
System.out.println(str1.equals(str3)); // true
}
// 字符串不区分大小写的比较: equalsIgnoreCase
public static void main(String[] args) {
String str1 = "hello";
String str2 = "Hello";
System.out.println(str1.equalsIgnoreCase(str2)); // true
}
// 比较两个字符串之间的大小关系: compareTo
// 按照字典顺序进行的比较
public static void main(String[] args) {
String str1 = "hello";
String str2 = "helloworld";
int ret = str1.compareTo(str2);
System.out.println(ret); // -5
System.out.println("A".compareTo("B")); // -1
System.out.println("AC".compareTo("AB")); // 1
}
public static void main(String[] args) {
String str1 = "hello";
String str2 = "helloworld";
int ret = str1.compareTo(str2);
System.out.println(ret); // -5
System.out.println("A".compareTo("B")); // -1
System.out.println("AC".compareTo("AB")); // 1
}
6.2 字符串的查找
- 判断一个字符串是否存在: contains
// 判断一个字符串是否存在: contains
public static void main(String[] args) {
String str = "abcdefg";
System.out.println(str.contains("abc")); // true
System.out.println(str.contains("acd")); // false
}
// 从头开始查找字符串的位置, 查到了返回开始位置的索引, 查不到就返回 -1: indexOf(String str)
public static void main(String[] args) {
String str = "abcdefg";
System.out.println(str.indexOf("cde")); // 2
System.out.println(str.indexOf("acd")); // -1
}
// 从指定位置开始查找字符串的位置: indexOf(String str, int fromIndex)
// 使用indexOf()需要注意的是,如果内容重复,它只能返回查找的第一个位置
public static void main(String[] args) {
String str = "abcdefg";
System.out.println(str.indexOf("cde", 1)); // 2
System.out.println(str.indexOf("bcd", 5)); // -1
}
// 从后向前查找子字符串的位置: lastIndexOf(String str)
public static void main(String[] args) {
String str = "abcdef";
System.out.println(str.lastIndexOf("bcd"));
}
// 判断是否以指定字符串结尾: endsWith
public static void main(String[] args) {
String str = "abcdef";
System.out.println(str.endsWith("g")); // true
}
// 从指定位置开始判断是否以指定字符串开头: startsWith(String prefix, int tOffset)
public static void main5(String[] args) {
String str = "abcdef";
System.out.println(str.startsWith("cde", 2)); // true
System.out.println(str.startsWith("cde", 1)); // false
}
// 判断是否以指定字符串开头: startsWith
public static void main4(String[] args) {
String str = "abcdef";
System.out.println(str.startsWith("abc")); // true
System.out.println(str.startsWith("acd")); // false
}
// 从指定位置由后向前查找: lastIndexOf(String str, int frontIndex)
public static void main3(String[] args) {
String str = "abcdef";
System.out.println(str.lastIndexOf("cde", 3)); // 2
System.out.println(str.lastIndexOf("cde", 1)); // -1
}
6.3 字符串的替换
// 替换首个内容
public static void main(String[] args) {
String str = "ababcabcd";
String s = str.replaceFirst("abc", "pp");
System.out.println(s); // abppabcd
}
// 替换一个字符串: replace(CharSequence target, CharSequence replacement) 等价于 replaceAll
public static void main(String[] args) {
String str = "ababcabcd";
String ret = str.replace("ab", "pp");
System.out.println(ret); // ppppcppcd
}
// 替换一个字符
public static void main(String[] args) {
String str = "ababcabcd";
String ret = str.replace('a', 'p');
System.out.println(ret); // pbpbcpbcd
}
6.4 字符串拆分
// 多次拆分(如果一个字符串中有多个分隔符,可以用"|"作为连字符)
public static void main(String[] args) {
String str = "name=wangwu&age=18";
String[] ret = str.split(" |&|=");
for (String s:ret) {
System.out.println(s);
}
}
// 按照一些特殊字符进行拆分: .$|()[{^? 这样的符号作为分割符时, 需要在其前加上 \\
public static void main(String[] args) {
String str = "192.168.1.1";
String[] ret = str.split("\\.");
for (String s:ret) {
System.out.println(s);
}
}
// 字符串的部分拆分
public static void main(String[] args) {
String str = "hello world !!!";
String[] s = str.split(" ", 2);
for (String s1:s) {
System.out.println(s1);
}
}
// 字符串按照空格拆分
public static void main(String[] args) {
String str = "hello world !!!";
String[] ret = str.split(" ");
for (String s:ret) {
System.out.println(s);
}
}
6.5 字符串的截取
public static void main(String[] args) {
String str = "helloworld";
String ret = str.substring(2);
System.out.println(ret); // lloworld
String ret1 = str.substring(3, 8);
System.out.println(ret1); // lowor 属于[ )
}
6.5 其他操作方法
// 字符串是否为空
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.isEmpty()); // false
}
// 字符串的长度
public static void main(String[] args) {
String str = "helloworld";
System.out.println(str.length()); // 10
}
// 大小写转换
public static void main(String[] args) {
String str = "heLloWoRld";
String s = str.toUpperCase();
System.out.println(s); // HELLOWORLD
String s1 = str.toLowerCase();
System.out.println(s1); // helloworld
}
// trim() 的使用(去掉字符串中的左右空格, 只留中间的空格)
public static void main(String[] args) {
String str = " hello world ";
String s = str.trim();
System.out.println(s); // hello world
}
7. StringBuffer 和 StringBuilder
字符串一旦声明了就不可变性
如果String不断的执行 += 操作, 就会产生大量的临时引用, 占用空间
为了方便字符串的修改, 引进了StringBuffer 和 StringBuilder
在StringBuffer 和 StringBuilder 中有一个append()方法. 用来优化String的拼接, 它只会产生一个引用, 并且它的操作都是对这一个引用进行的
public static void main(String[] args) {
StringBuffer stringBuffer = new StringBuffer();
stringBuffer.append("hello").append("world");
System.out.println(stringBuffer);
}
StringBuffer 和 StringBuilder 的区别:
StringBuilder 和 String 一般都用于单线程情况
StringBuffer 一般用于多线程情况(线程安全)