String类型有两种实例化的方法:
一种是直接赋值,如String str=“abc”;
另一种是通过new来实例化,如:String str=new String(“abc”);
通过一段测试代码,我们发现:
public static void main(String[] args) {
String str1="abc";
String str2="abc";
String str3=new String("abc");
System.out.println(str1==str2);//true
System.out.println(str1==str3);//false
}
结果运行如图:
为什么会这样呢?
原因是:String类型直接实例化与new实例化对象是不同的;
在字符串中“==”比较的是字符串的地址;equals比较的是字符串的内容;
如果采用直接赋值 法:
在JVM底层实际上会自动维护一个对象池(字符串对象池),如果现在采用了直接赋值的模式进行String类的对象实例化操作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。如果下次继续引用直接赋值的模式声明String类对象,此时对象池之中如若有指定内容,将直接进行引用;如若没有,则开辟新的字符串对象而后将其保存在对象池之中以供下次使用;
如果采用构造方法new实例化一个对象:
该实例化对象却不会入池,且即使对象池中有该字符串内容,它也会直接开辟新的内存存放该字符串,不会引用池中的任何字符串,与池中的内容完全无关;
所以针对上面的代码:
String str1=“abc”; 因为是直接赋值,所以就将该字符串内容直接入池了;
String str2=“abc”;直接赋值,发现字符串对象池中有该字符串内容,所以直接引用了该字符串;导致str1与str2是指向的同一个字符串对象;
String str3=new String(“abc”);new实例化对象,直接开辟新的内存空间,与上面的两个字符串完全无关,
但是在String类中提供了方法入池操作 public String intern() ;
通过该方法,可以将用new实例化的字符串对象方入对象池中,其工作的过程就会和String直接赋值法工作的过程一样;
public static void main(String[] args) {
String str1="qwe";
String str2=new String("qwe").intern();
System.out.println(str1==str2);//true
}
结果为:
且两种实例化对象的方式还有一点不同:
直接赋值法在实例化过程中只会创建一个堆内存空间:
如:String str=“Abc”;
在堆内存上创建一个字符串对象,使栈内存上的对象引用指向该字符串对象;
而通过构造方法实例化字符串对象的方法,在实例化过程中会创建两个堆内存空间:
如: String str=new String(“Abc”);
在实例化的过程中,首先会创建一个堆内存空间(1)存储字符串Abc,然后在new时,又创建了一个堆内存空间(2),存放该字符串对象,并使堆内存空间(1)成为垃圾空间,被回收,接着使栈里面的引用str指向该字符串对象;