Java 基础之 String 类
String
String 被声明为 final,因此不能被继承。(Integer 等包装类也不能被继承)
在 java8 中,String 内部使用 char 数组 来存储数据
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[];
}
在 java9 中,String 内部使用 byte 数组存储字符串,同时使用 coder 来标识使用了哪种编码
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final byte[] value;
/** The identifier of the encoding used to encode the bytes in {@code value}. */
private final byte coder;
}
value 数组被声明 final,因此 value 数组初始化之后就不能再引用其他数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变
String 不可变的好处
1. 可以缓存 hash 值
因为 String 的 hash 值经常被使用,例如 String 用做 HashMap 的 key。不可变的特性可以使得 hash 值也不可变,因此只需要进行一次计算。
2. String pool
如果一个 String 对象已经被创建过,那么就会从常量池中取的引用,只有 String 是不可变的,才能使用 String pool
3. 安全性
String 经常作为参数,String 不可变可以保证参数不可变,例如在作为网络连接参数的情况下如果 String 是可变的,那么在网络连接过程中,String 被改变,改变 String 的那一方以为现在连接的是其它主机,而实际情况却不一定是。
4. 线程安全
因为字符串是不可变的,所以是多线程安全的,同一个字符串实例可以被多个线程共享。这样便不用因为线程安全问题而使用同步。字符串自己便是线程安全的。
String, StringBuffer and StringBuilder
1. 可变性
String 不可变(String 类中使用 final 关键字修饰字符数组来保存字符串,所以 String 对象是不可变的。)
StringBuilder 与 StringBuffer是可变的(都继承AbstractStringBuilder,也是使用 char 数组保存数据,但是没有使用 final 修饰符)
AbstractStringBuilder:
abstract class AbstractStringBuilder implements Appendable, CharSequence {
/**
* The value is used for character storage.
*/
char[] value;
/**
* The count is the number of characters used.
*/
int count;
/**
* This no-arg constructor is necessary for serialization of subclasses.
*/
AbstractStringBuilder() {
}
}
2. 线程安全性
- String 不可变,线程安全(操作少量的数据使用)
- StringBuilder 线程不安全(单线程操作字符串缓冲区下操作大量数据)
- StringBuffer 线程安全,内部使用 synchronized 进行同步(多线程操作字符串缓冲区下操作大量数据)
String pool
字符串常量池(String Pool)保存着所有字符串字面量(literal strings), 这些字面量在编译时期就确定。不仅如此, 还可以使用 String 的 intern() 方法在运行过程将字符串添加到 String Pool 中。
当一个字符串调用 intern() 方法时,如果 String Pool 中已经存在一个字符串和该字符串值相等(使用 equals() 方法进行确定),那么就会返回 String Pool 中字符串的引用;否则,就会在 String Pool 中添加一个新的字符串, 并返回这个新字符串的引用。
下面示例中,s1 和 s2 采用 new String() 的方式新建了两个不同字符串,而 s3 和 s4 是通过 s1.intern() 方法取得同一个字符串引用。intern() 首先把 s1 引用的字符串放到 String Pool 中, 然后返回这个字符串引用。因此 s3 和 s4 引用的是同一个字符串。
String s1 = new String("aaa"); //堆内存中 s1为一个引用
String s2 = new String("aaa"); //堆内存中 s2为另一个引用
System.out.println(s1 == s2); // false
String s3 = s1.intern(); //s3为s1的引用
String s4 = s1.intern(); //s4为s1的引用
System.out.println(s3 == s4); // true
如果是采用 "bbb" 这种字面量的形式创建字符串,会自动地将字符串放入 String Pool 中。
String s5 = "bbb"; //放在常量池中
String s6 = "bbb"; //从常量池中查找
System.out.println(s5 == s6); // true
在 Java 7 之前,String Pool 被放在运行时常量池中,它属于永久代。而在 Java 7,String Pool 被移到堆中。这是因为永久代的空间有限,在大量使用字符串的场景下会导致 OutOfMemoryError 错误。
new String("abc")
使用这种方式会创建两个字符串对象,前提是常量池中还没有 “abc” 字符串对象
- “abc” 属于字符串字面量,因此编译时期会在 String Pool 中创建一个字符串对象,指向这个 “abc” 字符串字面量;
- 使用 new 的方式会在堆中创建一个字符串对象
------------恢复内容结束------------
最新文章
- js_原型
- GDB详解
- C#代码实现对HTTP POST参数进行排序
- smarty -- foreach用法
- php字符串与正则表达式试题 Zend权威认证试题讲解
- Linux操作系统报:read-only file system
- Prime Ring Problem + nyoj 素数环 + Oil Deposits + Red and Black
- UML之部署图(Deployment Diagram)
- hdu_5705_Clock(";巴卡斯杯"; 中国大学生程序设计竞赛 - 女生专场)
- GCD(关于容斥原理)
- java基础(一章)
- [IDE工具配置]myeclipse 2014 专业版 安装 svn插件
- 20190312_浅谈go&;java差异(一)
- CentOS7 Docker私有仓库搭建及删除镜像 【转】
- Android--Service之AIDL传递系统基本类型数据
- 解决Eclipse点击运行后控制台不能自动弹出的问题
- 【整理】Java 10新特性总结
- Notification 浏览器的消息推送
- XE4 for ios 谨慎处理字符串
- 深入探索C++对象模型(1) 关于对象(思维导图)