String的实例化方式有两种
直接赋值法
String str = "Hello";
构造法
String str = new String("Hello");
因为String作为引用数据类型,而且它比较特殊,所有使用" "定义的内容本质上来讲都是String的匿名对象
因为每个" "定义的内容本质上来讲都是String的匿名对象
所以除了new开辟的空间,"Hello"也会开辟空间,没有变量引用的"Hello"成为垃圾对象,最后被GC回收
构造法造成了空间的浪费,所以一般创建String对象我们都用直接赋值法
相比构造法,直接赋值法除了这个优点之外,还引入了一种共享设计模式 我们用代码来体现
String str1 = "hello" ;
String str2 = "hello" ;
String str3 = "hello" ;
System.out.println(str1 == str2); // true
System.out.println(str1 == str3); // true
System.out.println(str2 == str3); // true
创建了三个字符串对象,通过==比较三个对象的地址,却得到了三者是同一个对象的结论,这是为什么呢?
在JVM底层实际上会自动维护一个对象池(字符串对象池),如果现在采用了直接赋值的模式进行String类的对象 实例化操
作,那么该实例化对象(字符串内容)将自动保存到这个对象池之中。如果下次继续使用直接赋值的模式 声明String类对象,此
时对象池之中如若有指定内容,将直接进行引用;如若没有,则开辟新的字符串对象而后将 其保存在对象池之中以供下次使用
这也就是为什么咱们使用直接赋值法的第二个原因,所谓对象池看似名字高端,其本质也就是一个对象数组
那么构造法中的两个对象,一个匿名对象,一个new出来的对象,这两个对象有没有入池呢?
答案是都没有,匿名对象没有变量引用,成为垃圾对象并不会入池,那new出来的对象呢?这个问题要求证很简单
String str1 = new String("hello") ;
String str2 = "hello" ;
System.out.println(str1 == str2); // false
答案是没有,但是String类提供了入池方法 public String intern() ;
可以手动让构造法创建的对象入池
String str1 = new String("hello").intern() ;
String str2 = "hello" ;
System.out.println(str1 == str2); // true
结论:String类中两种对象实例化的区别
1. 直接赋值:只会开辟一块堆内存空间,并且该字符串对象可以自动保存在对象池中以供下次使用。
2. 构造方法:会开辟两块堆内存空间,其中一块成为垃圾空间,不会自动保存在对象池中,可以使用 intern()方法手工入池。
而我们采用的是第一种方式