Java学习总结之String类
1.常用方法
1.1字符串构造
-
使用常量串进行构造
String str = "hello world";
-
new String对象
String str = new String("hello world")
-
使用字符数组进行构造
char[] array={'h','e','l','l','o'}; String str = new String(array);
注意事项
- String是引用类型,内部并不存储字符串本身
- 在Java中""引起来的也是String类型对象
1.2String对象的比较
- ==比较是否引用同一个对象(比较的是对象的地址,内置类型比较的是值)
String s1 = new String("hello");
String s2 = new String("hello");
String s3 = new String("world");
String s4 = s1;
System.out.println(s1 == s2); // false
System.out.println(s2 == s3); // false
System.out.println(s1 == s4); // true
-
equals 方法:按照字典序比较
String类重写了父类Object中equals方法,Object中equals默认按照==比较。
String s1 = new String("hello"); String s2 = new String("hello"); String s3 = new String("world"); String s4 = s1; System.out.println(s1.equals(s2)); // true System.out.println(s2.equals(s3)); // false System.out.println(s1.equals(s4)); // true
-
comareTo方法:按照字典序顺序比较
public static void main(String[] args) { String s1 = new String("abc"); String s2 = new String("ac"); String s3 = new String("abc"); String s4 = new String("abcdef"); System.out.println(s1.compareTo(s2)); // 不同输出字符差值-1 System.out.println(s1.compareTo(s3)); // 相同输出 0 System.out.println(s1.compareTo(s4)); // 前k个字符完全相同,输出长度差值 -3 }
-
compareToIgnore方法:与compareTo方式相同,但是忽略大小写比较
public static void main(String[] args) { String s1 = new String("abc"); String s2 = new String("ac"); String s3 = new String("ABc"); String s4 = new String("abcdef"); System.out.println(s1.compareToIgnoreCase(s2)); // 不同输出字符差值-1 System.out.println(s1.compareToIgnoreCase(s3)); // 相同输出 0 System.out.println(s1.compareToIgnoreCase(s4)); // 前k个字符完全相同,输出长度差值 -3 }
1.3字符串查找
常用的查找方式
方法 | 功能 |
---|---|
char charAt(int index) | 返回index位置上字符,如果index为负数或者越界,抛出 IndexOutOfBoundsException异常 |
int indexOf(int ch) | 返回ch第一次出现的位置,没有返回-1 |
int indexOf(int ch, int fromIndex) | 从fromIndex位置开始找ch第一次出现的位置,没有返回-1 |
int indexOf(String str) | 返回str第一次出现的位置,没有返回-1 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始找str第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch) | 从后往前找,返回ch第一次出现的位置,没有返回-1 |
int lastIndexOf(int ch, int fromIndex) | 从fromIndex位置开始找,从后往前找ch第一次出现的位置,没有返 回-1 |
int lastIndexOf(String str) | 从后往前找,返回str第一次出现的位置,没有返回-1 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找,从后往前找str第一次出现的位置,没有返 回-1 |
1.4转化
-
数值与字符串相互转化
String s1 = String.valueOf(1234); //数值转字符串 int sum = Integer.parseInt(s1); //字符串转数值
-
大小写转换
String s1 = "hello"; String s2 = "HELLO"; s1.toUpperCase(); //s1 = "HELLO" s2.toLowerCase(); //s2 = "hello"
-
字符串转数组
String s = "hello"; // 字符串转数组 char[] ch = s.toCharArray(); // 数组转字符串 String s2 = new String(ch);
-
格式化
String s = String.format("%d-%d-%d", 2022, 8,12); System.out.println(s); //执行结果 2022-8-12
1.5字符串替换
String str = "helloworld" ;
System.out.println(str.replaceAll("l", "-"));
// replaceAll替换指定的所有内容
System.out.println(str.replaceFirst("l", "-"))
//replaceFirst替换指定的首个内容
//执行结果
he--owor-d
he-loworld
1.6字符串拆分
-
字符串全部拆分
String str = "hello world" String[] result = str.split(" ") ; // 按照空格拆分 for(String s: result) { System.out.println(s); } //执行结果 hello world
-
字符串部分拆分
String str = "hello world hello world" ; String[] result = str.split(" ",2) ; for(String s: result) { System.out.println(s); } //执行结果 hello world hello world
注意事项
- 字符"|“,”*“,”+"都得加上转义字符,前面加上 “\” .
- 而如果是 “” ,那么就得写成 “\\” .
- 如果一个字符串中有多个分隔符,可以用"|"作为连字符
1.7字符串的截取
-
从指定索引截取到结尾
String str = "helloworld" ; System.out.println(str.substring(5)); //执行结果 world
-
截取部分内容
String str = "helloworld" ; System.out.println(str.substring(0,5)); //执行结果 hello
注意事项
- 注意前闭后开区间的写法, substring(0, 5) 表示包含 0 号下标的字符, 不包含 5 号下标
1.8字符串去掉去掉空格
String str = " hello world " ;
System.out.println("["+str+"]");
System.out.println("["+str.trim()+"]");
//执行结果
[ hello world ]
[hello world]
2.字符串常量池
2.1创建对象方式的不同
当以不同的方式创建字符串的时候:
String str1="hello";
String str2="hello";
String str3=new String("world");
String str4=new String("world");
System.out.println(str1==str2); //true
System.out.println(str1==str3); //false
System.out.println(str3==str4); //false
可以看到当以以字符常量串创建的时候,创建的字符串的地址一样,而用new String的时候结果的地址是不一样的,简单地说就是str1和str2引用的对象是一样的,而str3和str4不一样。
为了使程序的运行速度更快、更节省内存,Java为8种基本数据类型和String类都提供了常量池。
为了节省存储空间以及程序的运行效率,Java中引入了:
-
class文件常量池:每个.Java源文件编译后生成.class文件中会保存当前类中的字面常量以及符号信息
-
运行时常量池:在.class文件被加载时,.class文件中的常量池被加载到内存中称为运行时常量池,运行时常量池每个类都有一份
-
字符串常量池
2.2字符串常量池(String Table)
字符串常量池在JVM中是StringTable类,实际是一个固定大小的HashTable(一种高效用来进行查找的数据结构)不同JDK版本下字符串常量池的位置以及默认大小是不同的
JDK版本 | 字符串常量池位置 | 大小设置 |
---|---|---|
Java6 | (方法区)永久代 | 固定大小:1009 |
Java7 | 堆中 | 可设置,没有大小限制,默认大小:60013 |
Java8 | 堆中 | 可设置,有范围限制,最小是1009 |
2.3String对象的创建
-
直接使用字符串常量进行赋值
String str1="hello"; String str2="hello"; System.out.println(str1==str2); //true
当字节码文件加载的时候字符串hello已经创建好了并且保存在字符串常量池中,当使用常量串赋值的时候优先从字符串常量池找,找到了就将该字符串引用赋值给要赋值的对象。 因此会出现这两个字符串地址一致。
-
通过new创建String类的对象
String str3=new String("world"); String str4=new String("world"); System.out.println(str3==str4);
- 当我们用new来创建String对象的时候,由于new的对象是唯一的,所以地址都是不一样的。
- 使用常量串创建String类型对象的效率更高,而且更节省空间。用户也可以将创建的字符串对象通过intern方式添加进字符串常量池中。
2.4intern方法
intern是一个native方法(Native方法指:底层使用C++实现的,看不到其实现的源代码),该方法的作用是手动将创建的String对象添加到常量池中。
public static void main(String[] args) {
char[] ch = new char[]{'a', 'b', 'c'};
String s1 = new String(); // s1对象并不在常量池中
//s1.intern();
String s2 = "abc"; // "abc" 在常量池中存在了,s2创建时直接用常量池中"abc"的引用
System.out.println(s1 == s2); //false
char[] ch = new char[]{'q', 'w', 'e'};
String s3 = new String(); // s3对象并不在常量池中
s1.intern();
String s2 = "qwe"; // "abc" 在常量池中存在了,s2创建时直接用常量池中"abc"的引用
System.out.println(s3 == s4); //true
}
2.6字符串的不可变性
- String类在设计时就是不可变性的,String类中的字符实际保存在内部维护的value数组中,该数组被final修饰,表示value自身的值不可变即不能引用其它字符数组,但是其引用空间中的内容可以修改。
- String类被final修饰,表明该类不能被继承
- 所有涉及到可能修改字符串内容的操作都是创建一个新对象,改变的是新对象
不可变的对象的好处:
- 方便实现字符串对象池. 如果 String 可变, 那么对象池就需要考虑写时拷贝的问题了.
- 不可变对象是线程安全的.
- 不可变对象更方便缓存 hash code, 作为 key 时可以更高效的保存到 HashMap 中
3.StringBuffer和StringBuilder
3.1常用方法
方法 | 说明 |
---|---|
StringBuff append(String str) | 在尾部追加,相当于String的+=,可以追加:boolean、char、char[]、 double、float、int、long、Object、String、StringBuff的变量 |
char charAt(int index) | 获取index位置的字符 |
int length() | 获取字符串的长度 |
int capacity() | 获取底层保存字符串空间总的大小 |
void ensureCapacity(int mininmumCapacity) | 扩容 |
void setCharAt(int index, char ch) | 将index位置的字符设置为ch |
int indexOf(String str) | 返回str第一次出现的位置 |
int indexOf(String str, int fromIndex) | 从fromIndex位置开始查找str第一次出现的位置 |
int lastIndexOf(String str) | 返回最后一次出现str的位置 |
int lastIndexOf(String str, int fromIndex) | 从fromIndex位置开始找str最后一次出现的位置 |
StringBuff insert(int offset, String str) | 在offset位置插入:八种基类类型 & String类型 & Object类型数据 |
StringBuffer deleteCharAt(int index) | 删除index位置字 |
StringBuffer delete(int start, int end) | 删除[start, end)区间内的字符 |
StringBuffer replace(int start, int end, String str) | 将[start, end)位置的字符替换为str |
String substring(int start,int end) | 将[start, end)范围内的字符以String的方式返回 |
String substring(int start) | 从start开始一直到末尾的字符以String的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照String的方式返回 |
3.2String类与StringBuilder或StringBuffer类的相互转换
String和StringBuilder类不能直接转换。如果要想互相转换,可以采用如下原则:
-
String变为StringBuilder: 利用StringBuilder的构造方法或append()方法
String str = "abc"; //第一种方法 StringBuilder stb = new StringBuilder(str); //第二种方法 StringBuilder stb1 = new StringBuilder(); stb1.append(str);
-
StringBuilder变为String: 调用toString()方法
StringBuilder stb = new StringBuilder("abc"); String str = stb.toString();
3.3String,StringBuilder和StringBuffer类的异同
- 相同点:底层都是通过char数组实现的
- 不同点:
- String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
- StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
- 如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder;