JVM学习笔记-03-常量池

关于常量池

常量池是方法区的一部分:


(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拼接的整个过程,到最后的实现变成了数组的扩容和复制过程.

这里提一个问题假如有这样一段代码:

final StringBuffer sb = new StringBuffer();
//问这个时候还能使用sb.append()方法添加元素吗
当final修饰以后这个对象以后其实他还是可以继续调用append()方法区添加元素的,只不过呢,这个时候这个元素的引用是不能修改了,但是他添加的元素并没有被限制.同理如果一个List也被final修饰时,也是可以使用add()去添加元素.

(2017年8月14日16:07:58)

2.常量池中包含的class信息

常量池中存放的class相关信息包含,类名,访问修饰符,常量池,字段描述,方法描述等.在实际的开发中我们使用的主流框架如:String,Hibernate,都做了动态产生类的加强,它们可以直接字节码在运行时产生大量的动态类.这就需要方法区保证能够大量的加载这些动态产生的类.

这里要特别说一下我们常用的常量

private static final String str = "helloWord";

常量是在编译时就已经确定了,直接调用就可以,不用加载相应的类.

(2017年8月14日17:11:51)

你可能感兴趣的:(JVM学习笔记)