
public static void main(String[] args) {
// 1. 常量字符串构造(推荐!!!)
String s1 = "abc";
System.out.println(s1);
// 2. 使用new构造对象(不推荐!!!)
String s2 = new String("abc");
System.out.println(s2);
// 3. 使用字节数组构造(还是会转变成字符处理)
byte[] arr = new byte[]{ 97, 98, 99 };
String s3 = new String(arr);
System.out.println(s3);
}☘注意事项:
String 是引用类型,底层并不存储字符串本身!
2. 对于上面第一种构造方式来说,实际上是对常量池中 "abc" 的一个引用,如果此时再创建一个 String s2 = "abc",此时并不会真的又去开辟一段空间,而是让 s2 指向常量池中的 "abc",减少内存开销,所以在使用 s1==s2 的时候虽然结果是 true 看起来是对的,但实际上比较的仍然是一个相同的地址,而不是比较字符串内容!
3. 接上一点,String s1 = new String("abc") 是在堆区开辟空间,而 String s2 = "abc" 是引用一个常量池中的空间,是不一样的!
4. 在 Java 中 "" 引起来的也是 String 类型对象。
5. String 对象不能使用中括号访问某个字符,如 s[0] 是不允许的!
boolean isEmpty():检查字符串是否为空(即长度为 0)boolean isBlank():方法用于检查字符串是否为空白字符串(即字符串为空或仅包含空白字符)==:对于内置类型,比较的是变量中的值;对于引用类型,比较的是引用中的地址boolean equals(Object anObject):按照字典序比较是否相同int compareTo(String s):按照字典序进行比较大小,返回差值boolean equalsIgnoreCase(String str):与 equals 相同,但是忽略大小写比较int compareToIgnoreCase(String str):与 compareTo 相同,但是忽略大小写比较char charAt(int index):返回 index 下标处字符,如果 index 为负数或者越界,抛出 IndexOutOfBoundsException 异常int indexOf(int ch):返回 ch 第一次出现的位置,没有返回 -1int lastIndexOf(int ch):从后往前找,返回 ch 第一次出现的位置,没有返回 -1String.valueOf(xxx)Integer.parseInt(xxx)、Double.parseDouble(xxx) 等等String toUpperCase()String toLowerCase()char[] toCharArray()String str = new String(arr);String s = String.format("%d-%d-%d", 2019, 9,14);String replace(char oldChar, char newChar)replaceFirst、replaceAll 以及重载版本,可以替换对应字符串而不只是字符!String[] split(String regex)String[] split(String regex, int limit):将字符串以指定的格式,拆分为 limit 组|,*,+ 都是功能字符,所以得加上转义字符,即在前面加上 \\。 \,那么就得写成 \\\\。| 作为连字符,如下面代码所示:public static void main(String[] args) {
String s = "lianwi&Nkqnwl%oino123)asd|kk";
String[] ret = s.split("&|%|\\)|\\|"); // 让&、%、)、|作为分隔符,彼此之间用|连接起来!
System.out.println(Arrays.toString(ret));
}
// 结果:
[lianwi, Nkqnwl, oino123, asd, kk]String substring(int beginIndex):从指定索引截取到结尾String substring(int beginIndex, int endIndex):截取部分内容String trim():去掉字符串中的左右空白(注意不只是空格)public String intern(),这个方法是用于一些大型项目需要减少内存的开销,将大量重复的字符串放入到常量池等等池中进行维护。如下面代码所示:String s1 = new String("hello");
String s2 = "hello"; // 引用常量池中的对象
System.out.println(s1 == s2); // false(s1是堆对象)
System.out.println(s1.intern() == s2); // true(s1.intern()返回常量池中的引用)String 是一种不可变对象。字符串中的内容是不可改变,如果有修改的需求,只能通过创建一个新的对象来引用新的字符串,而不能在原来的字符串上进行修改!

如上图所示,value 字符数组被 final 修饰,所以不能引用其它的字符数组,不过它是可以修改字符数组的内容的;但由于它又被 private 修饰,并且类内没有提供设置字符数组内容的接口,所以整体下来就达到了不能修改引用、不能修改内容的效果!
注意比如说 String s = "abc" 不能修改指的是 "abc" 不能修改,而不是说 s 不能修改,s 是可以引用其它字符串的!
为什么
String要设计成不可变的?(不可变对象的好处是什么?)
String 可变,那么对象池就需要考虑写时拷贝的问题,因为一个字符串有多个对象引用。hashcode,作为 key 时可以更高效的保存到 HashMap 中。StringBuilder 其实就相当于 C++ 中的 std::string,而 String 就相当于是 C++ 中的字符串常量。
也就是说 StringBuilder 的增删改都是在原来的字符串(更准确来说是字符数组)进行修改,而不像 String 一样是通过创建新的字符串,大大减少了增删改的开销!
方法 | 说明 |
|---|---|
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) | 从 start 开始一直到末尾的字符以 String 的方式返回 |
String substring(int start,int end) | 将 [start, end) 范围内的字符以 String 的方式返回 |
StringBuffer reverse() | 反转字符串 |
String toString() | 将所有字符按照 String 的方式返回 |
注意:String 和 StringBuilder 不能直接转换。如果要想互相转换,可以采用如下原则:
String --> StringBuilder: 利用 StringBuilder 的构造方法或 append() 方法 StringBuilder --> String: 调用 toString() 方法。package StringLearning;
/**
* 测试一下String和StringBuilder的速度
*/
public class demo {
public static void main(String[] args) {
String s1 = "";
StringBuilder s2 = new StringBuilder();
long start1 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
s1 += i;
}
long end1 = System.currentTimeMillis();
long start2 = System.currentTimeMillis();
for (int i = 0; i < 100000; i++) {
s2.append(i);
}
long end2 = System.currentTimeMillis();
System.out.println("String: " + (end1 - start1) + "ms");
System.out.println("StringBuilder: " + (end2 - start2) + "ms");
}
}
// 结果
String: 2391ms
StringBuilder: 1ms特性 | StringBuilder | StringBuffer |
|---|---|---|
线程安全 | ❌ 不安全 | ✅ 线程安全(内部方法加了 synchronized) |
适合场景 | 单线程环境下的字符串拼接 | 多线程环境下安全地修改字符串 |
性能表现 | 🚀 更快 | 🐢 稍慢 |
引入版本 | Java 5 | Java 1.0 |
使用方式 | 相同(API 几乎一模一样) | 相同 |
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。