String类的零碎知识点
1、关于==和equals
前者是引用一致判断,对内存中引用对象的比较,如果两个对象指向了同一个内存空间(或叫内存地址,封装一下叫引用对象),则返回true;
后者是自定义的比较,如果不重写equals默认和==一样,但是后者可以通过改写hashcode和equals方法来实现自定义比较;
相比==,equals更注重内容一致性判断;
对于==返回ture的,equals一定返回true;反之则不一定。
2、对于String类的赋值:new String(“abc”)&& “abc”
String str1 = new String(“abc”);
String str2 = “abc”;
String str3 = new String(“abc”);
String str4 = “abc”;
String str5 = “ab”+”c”;
- 对于str1,虚拟机直接在堆区创建一个对象,然后让str1指向该对象;
- 对于str2,虚拟机先去String Pool里寻找是否存在和“abc”相等的字符串对象,如果有,则将str2指向String pool中的字符串地址;
- 对于str3,虚拟机直接在堆区创建一个对象,虽然str1已经创建了一个内容相同的对象,但是str4还是会创建一个对象,所以str1==str4返回false,因为他们指向了不同的对象;
- 对于str4,虚拟机会先去String pool寻找与“abc”内容相同的对象,发现存在了(如果之前没有,str2也创建了),所以str4就直接指向了String Pool中的“abc”,所以str2==str4返回true;
- 对于str5,会将字符串先进行表达式计算,然后放入字符串池中,即str2==str5返回true;
String ab = “ab”;
String c = “c”;
- 对于变量的拼接或者变量和常量的拼接(ab+“c”),String类会按照new一个字符串的方式在堆区创建一个对象,即ab+c==str2返回false;
3、 对于String类的intern方法
String str6 = str1.intern();
- Intern方法会返回一个将str1放入String Pool的指针(如果池中没有,则加入),此时str2==str6会返回true;
- 但是intern方法并不会改变str1的指针,即str1==str2依然返回false;
- 该方法的实现是一个本地(native)方法;
4、String Pool
- 对于字符串池,一般来说,当一个字符串进入到字符串池中,如果没有了外部引用,也不会被垃圾回收,因为字符串池不会被垃圾回收,所以这样可能会导致内存泄漏;
- 在虚拟机中,这一块称为String常量池的区间专门用于存放字符串常量。在JDK 1.6之前,这块区间属于永久区的一部分,但是在JDK 1.7以后,它就被移到了堆中进行管理。
- 可以通过以下代码测试:
public static void main(String[] args) {
List<String> list = new ArrayList<String>();
int i = 0;
while(true){
list.add(String.valueOf(i++).intern());
}
}
//JVM参数设置为:-Xmx5m -XX:MaxPermSize=5m
- 当JDK版本大于1.7的时候,会报错:java.lang.OutOfMemoryError: Java heap space
- 而低于1.7的则会报错:java.lang.OutOfMemoryError: PermGen space