一般的对象都是通过new
进行创建的,但是String
有两种创建方式。
也就是我们常用的直接声明的方式,比如String str="abc"
,通过直接量"abc"进行赋值,这种方式是极力推荐的。为什么呢?我们来看一个情况:
public class Client{
public static void main(String[] args){
String str1 = "a";
String str2 = "a";
String str3 = new String("a");
String str4 = str3.intern();
System.out.println(str1 == str2);
System.out.println(str1 == str3);
System.out.println(str1 == str4);
}
}
运行结果:
true
false
true
我们知道 "=="
是用来判断了两个对象是否为同一个对象的,"intern()"
方法是干嘛用的呢?
原来在java里面为了避免在一个系统中大量产生String对象(为什么大量产生,因为String字符串在程序中是最常用的类型),于是设计了一个字符串常量池
的东西.
和我们数据库连接池的概念差不多,当我们采用直接声明的方式而不是new
的方式创建字符串的时候,程序会首先检查池中有没有字面值和当前声明的字符串变量一样的字符串,如果有就返回池中该对象的引用,否则就创建这个字符串,然后把新对象投入池中,并返回新对象的引用。
"intern()"
方法所做的事情就是这样的事情,由于new
创建的对象,程序是不会主动去执行这个操作的,所以我们手动执行了下这个操作,于是就有了 str1 == str4
的返回值为true
你可能会问这样做会不会有线程安全问题?要不要考虑字符串常量池的垃圾回收问题?
1. 其实 String
类型本身就是一个final
的类,所以不可能被继承,也就不可能出现 String
的派生类了,其次 String
的方法如果是 String
的返回值,就会重新创建一个 String
对象,并不会对原来的对象进行修改,这也就是String的不可变性
,既然都不可变了,就像常量一样那么也就不存在什么线程安全问题了。
2. 字符串常量池从编译期开始就是存在于JVM的常量池中,垃圾回收主要是回收堆区的内存,并不会回收常量池的东西。
网友评论