1、String类为什么被final修饰?
主要从两方面考虑,安全性和性能。我们知道String使用频率很高,在多线程环境中,如果String不是被final修饰,那么必须使用锁机制来保证线程的安全性,这样就影响了整个系统的性能;
2、String实例在JVM的位置?
1)想一下,下面String a ="String"将产生几个对象?
public class StringDemo1 { public static void main(String[] args) throws Exception { String a = "String"; CyclicBarrier barrier = new CyclicBarrier(2); barrier.await(); } }
通过 OQL来查询一下,结果如下:
2)如果使用new String创建字符串,又会产生几个实例?
public class StringDemo1 { public static void main(String[] args) throws Exception { String a = new String("String"); CyclicBarrier barrier = new CyclicBarrier(2); barrier.await(); } }
3)还有如下代码会产生几个对象?
public class StringDemo1 { public static void main(String[] args) throws Exception { String a = new String("String"); String b = new String("String"); CyclicBarrier barrier = new CyclicBarrier(2); barrier.await(); } }
我们知道凡是被final修饰的成员变量就是常量,一旦赋值就无法改变。在JVM中的常量池(1.7之前包含1.7在方法区,1.7之后移动Java堆中)分为三种静态常量池和运行时常量池。静态常量池保存Class不仅仅包含字符串(数字)字面量,还包含类、方法的信息,占用class文件绝大部分空间;运行时常量池,则是jvm虚拟机在完成类装载操作后,将class文件中的常量池载入到内存中,并保存在方法区中,我们常说的常量池,就是指方法区中的运行时常量池。
在Java文件编译时,预先声明的String字符串,在Java运行时,载入常量池。而使用new String(字符串)创建的字符串,在堆中创建一个对象,私有成员变量value指向常量池对象字符串的value引用。如果在运行时生成字符串,使用intern()方法,将常量池存放一个指向堆中对象的引用。
最后,将String源码中构造函数贴过来。
public String(String original) { this.value = original.value; this.hash = original.hash; } public String(char value[]) { this.value = Arrays.copyOf(value, value.length); }