(1)创建字符串对象
//方式1
String str = "abc";
//方式2
String str = new String("abc");
方式1表示:在字符串常量池(String Pool)中先寻找值为 “abc” 的内存地址,如果找不到,则开辟内存,赋值该内存地址为 “abc”,然后将该内存地址传递给变量 str,str 直接指向字符串常量池中值为 “abc” 的内存地址。
方式2表示:先在堆(Heap)空间中开辟空间,new String对象,然后再去字符串常量池中寻找值为 “abc” 的地址,如果找到,则把该地址的引用传给 new String对象;如果找不到,则开辟内存,赋值该内存地址为 “abc”,然后把该地址的引用传给 new String对象。最后,把堆空间中 new String 对象的地址,传递给 str,str 指向堆空间中的对象。
(2)intern()
public class HelloWorld {
public static void main(String[] args) {
String s1 = new String("hello") + new String("world");
s1.intern();
String s2 = "helloworld";
System.out.println(s1==s2);
}
}
jdk1.6输出:false
jdk1.8输出为:true
String s1 = new String("hello") + new String("world");
这句代码会在堆中new一个String对象(其实并没有这么简单,后面讲)
s1.intern();
s1调用了intern方法,然后发现在StringTable中并没有所对应的字符串,
那么jvm就会在StringTable中放入一个地址,这个地址指向s1所new的String对象。
String s2 = "helloworld";
jvm发现在StringTable中已经存在指向"helloworld"的地址了,就会把StringTable中的
地址给s2。此时s1和s2都指向这个地址。所以是同一个对象。于是返回了true
public class HelloWorld {
public static void main(String[] args) {
String s1 = new String("hello") + new String("world");
String s2 = "helloworld";
s1.intern();
System.out.println(s1==s2);
}
}
jdk1.8输出为:false
方法区是《Java虚拟机规范》中规定的一个内存区域,它用于存储已被虚拟机加载的类型信息、常量、静态变量、即时编译器编译后的代码缓存等。
元空间是方法区的实现。方法区的实现,JDK1.7之前是永久代,JDK1.8之后是元空间。
永久代在物理上是堆的一部分,元空间内存是操作系统本地内存。
Jdk1.7之前类的元数据、静态变量、字符串常量池都是在永久代
jdk1.8之后类的元数据在本地内存,静态变量和字符串常量在堆内存,相当于方法区只有类的元数据