关于常量池
常量池是方法区的一部分:
(2017年8月14日14:17:00)
1.String常量池
String这个类型是Java开发中最使用的类型:
String类型是由final修饰的,它是常量池中最常见的一种类型.
` public static void main(String[] args){
String str = "helloword";
String str1 = new String("helloword");
System.out.println(str==str1);// 运行后结果为false
}`
这里为什么是false呢,str1在new的过程中放在了堆引用,而str是放在常量池中的引用,而’==’对比的是引用信息,所以是false.
使用String.intern()方法
public static void main(String[] args){
String str = "helloword";
String str1 = new String("helloword");
System.out.println(str==str1);// 运行后结果为false
str1.intern();
System.out.pritln(str==str1);//运行结果是true
}
这里这个str1.intern();这个方法是一个native方法,它是看String常量池中有没有这个引用如果有,则返回这个常量池引用,如果没有则把它放到常量池中.
当然现在说的这些也只是在JDK1.6包含之前的版本出现的问题,JDK1.7中JVM把String常量区从方法区中移除了;JDK1.8中JVM把String常量池移入了堆中,同时取消了“永久代”,改用元空间代替(Metaspace).
关于字符串的大量拼接问题及其实现
这里想在探究一下String的批量拼接处理问题,这里我们知道String的拼接我们使用:”+”;拼接都会在堆中new一个新的对象,使用一个String.intern()方法放入常量池中,并且将新的引用返回,这时因为之前创建的对象还在,只是将他的引用改变了而已,当大量的拼接String类型的操作中会带来很大的内存开销,这个时候我们一般会使用StringBufer or StringBuilder,这里就不具体的讨论他们的区别了,让我们看一下他们的源码实现:
以StringBuilder为例:
StringBuilder也是final修饰的,并且继承自一个抽象的AbstractStringBuilder类
其实String和StringBuilder都是通过数组实现的,就是这个
char[] value;
这里不表,我们接着看源码;
我们在拼接String的时候一般是这些写的;
StringBuilder sb = new StringBuilder("hello");
sb.append("word");
这里初始化长度是 入参的length+16,16是初始化长度,
这里append()这个方法是写在AbstractStringBuilder类中的
这里 1 处方法是扩容,刚才提到String是通过数组实现的,他这个主要是为了保证数组空间够用,
这里 2 处方法是我们的StringBuilder,拼接的核心处理方法,
这里 1 处的System.arrayCopy()方法是个Native方法
这里大概是StringBuilder的append()方法处理整个String拼接的整个过程,到最后的实现变成了数组的扩容和复制过程.
(2017年8月14日16:07:58)
2.常量池中包含的class信息
常量池中存放的class相关信息包含,类名,访问修饰符,常量池,字段描述,方法描述等.在实际的开发中我们使用的主流框架如:String,Hibernate,都做了动态产生类的加强,它们可以直接字节码在运行时产生大量的动态类.这就需要方法区保证能够大量的加载这些动态产生的类.
这里要特别说一下我们常用的常量
private static final String str = "helloWord";
常量是在编译时就已经确定了,直接调用就可以,不用加载相应的类.
(2017年8月14日17:11:51)