String 为什么不可变?
先看下Java8 String类的源码:
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
/** Cache the hash code for the string */
private int hash; // Default to 0
}
String类是final的,它的所有成员变量也都是final的。为什么是final的?
- 线程安全。同一个字符串实例可以被多个线程共享,因为字符串不可变,本身就是线程安全的。
- 支持hash映射和缓存。因为String的hash值经常会使用到,比如作为 Map 的键,不可变的特性使得 hash 值也不会变,不需要重新计算。
- 字符串常量池优化。String对象创建之后,会缓存到字符串常量池中,下次需要创建同样的对象时,可以直接返回缓存的引用。
String、StringBuffer和StringBuilder类
String是不可变类,一旦String对象被创建,这个对象包含的字符串序列就不可改变,直到该对象被销毁。
StringBuffer对象则代表一个字符序列可变的字符串,可通过一系列方法改变字符串,如append(), insert(), remove(), 最后在通过toString()方法将其转换为String对象。
从JDK1.5新增StringBuilder类。它和StringBuffer基本相似。
不同的是,StringBuffer是线程安全的;StringBuilder没有实现线程安全功能,所以性能略高。(因此需要创建一个内容可变的字符串对象,优先考虑StringBuilder)
以上三者,都实现了CharSequence接口,因此CharSequence可以认为是字符串协议接口。
常见操作如下:
public static void main(String[] args) {
String s = new String("abcdefghijk");
// 字符串的序列从0开始到length()-1
System.out.println(s.charAt(5)); // f
String s1 = new String("abcdefghijk");
String s2 = new String("abcdefghijklmn");
String s3 = new String("abcdefghijkabcde");
// 比较两个字符串的大小。
// 如果两个字符串的字符序列相等,则返回0;不相等时,从两个字符串第0个字符开始比较,返回第一个不相等的字符差
// 另一个情况,较长的字符串的前面部分恰巧是较短的字符串,则返回它们的长度差。
System.out.println(s.compareTo(s1)); // 0
System.out.println(s2.compareTo(s3)); // 返回'l'-'a'的差
System.out.println(s1.compareTo(s2)); // 返回长度差
StringBuilder sb = new StringBuilder();
sb.append("java"); // java
sb.insert(0, "Hello "); //Hello java
sb.replace(5, 6, ","); //Hello,java
sb.delete(5, 6); //Hellojava
// 反转
sb.reverse(); //avajolleH
System.out.println(sb.toString());
System.out.println(sb.length()); //9
System.out.println(sb.capacity()); //16
// 只保留指定长度
sb.setLength(6);
System.out.println(sb.toString()); // avajol
}
区别
- 可变性
String 不可变
StringBuffer 和 StringBuilder 可变 - 线程安全
String 不可变,因此是线程安全的
StringBuilder 不是线程安全的
StringBuffer 是线程安全的,内部使用 synchronized 进行同步
String 类的常用方法有哪些?
indexOf():返回指定字符的索引。
charAt():返回指定索引处的字符。
replace():字符串替换。
trim():去除字符串两端空白。
split():分割字符串,返回一个分割后的字符串数组。
getBytes():返回字符串的 byte 类型数组。
length():返回字符串长度。
toLowerCase():将字符串转成小写字母。
toUpperCase():将字符串转成大写字符。
substring():截取字符串。
equals():字符串比较。
new String(“hello”)会创建几个对象?
使用这种方式会创建两个字符串对象(前提是字符串常量池中没有 “hello” 这个字符串对象)。
“hello” 属于字符串字面量,因此编译时期会在字符串常量池中创建一个字符串对象,指向这个 “hello” 字符串字面量;
使用 new 的方式会在堆中创建一个字符串对象。
什么是字符串常量池?
字符串常量池保存着所有字符串字面量,这些字面量在编译时期就确定。字符串常量池位于堆内存中,专门用来存储字符串常量。在创建字符串时,JVM首先会检查字符串常量池,如果该字符串已经存在池中,则返回其引用,如果不存在,则创建此字符串并放入池中,并返回其引用。
获取String字节长度
public int length()返回此字符串的长度。长度等于字符串中 Unicode 代码单元的数量。
需要使用下面的方式获取字节长度:
public static void main(String[] args) throws UnsupportedEncodingException {
String a = "123abc";
int num = a.getBytes(StandardCharsets.UTF_8).length;
System.out.println(num);
a = "中文";
num = a.getBytes(StandardCharsets.UTF_8).length;
System.out.println(num);
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/155639.html