JAVA 常量池与String

  提到常量池,一般是指运行时常量池,是方法区的一部分。方法区就是通常说的永久代。那么常量池中会存储那些数据呢?

  ①编译期生成的各种字面量和符号引用
  ②也有可能将运行期间的常量放入常量池


  先看第一种:编译期生成的各种字面量和符号引用,这部分数据经过编译后存在.class文件的‘常量池’中,注意这个所谓的‘常量池’是‘静态常量池’,静态常量池的数据会在类加载后放入运行时常量池。举个例子
  测试一

public class ConstantPoolAndStrTest {
    String string1 = "Hello";
    public void methodTest(){
        String string2 = "pool";
    }
}

  将上面代码编译后生成ConstantPoolAndStrTest.class文件,现在我们要想知道数据成员string1=“Hello”和局部变量string2=”pool“会不会进入常量池,只需要解析ConstantPoolAndStrTest.class文件,看其常量池(静态)中是否包含“Hello”和“pool”。而.class文件中存储的是只有JVM能够读懂的字节码,所以我们要想识别其内容要借助JDK自带的反汇编工具javap。执行命令javap -verbose ConstantPoolAndStrTest.class 可以得到下面数据:


  上图只贴出了常量池(静态)的数据。可以看到string1和string2都被放入了常量池,而这部分数据会在类加载后放入运行时常量池。
  经过同上的测试发现:
测试二

String strTest = "my"+"string";

编译期会将上面代码优化为strTest="mystring","mystring"被存入常量池中,但"my"和"string"并没有进入常量池。
测试三

String string1 = "a";
String string2 = "b";
String string3 = string1+string2;
String string4 = string1+"c";


  上面的代码,string3="ab"和string4="bc"都没有进入常量池。结合测试二、测试三可知:java编译器会对字面量的运算(测试一)进行优化,但不会对含有引用的运算(测试二)进行优化。
  下面说一个稍微绕一点的情况:
测试四

  String newStrtest = new String("pool");

编译,javap 可得到下面结果


  到这里可能会有一点迷惑了:
  new String("pool")不是在堆中创建对象么?怎么会跑到了常量池里?
  没错,new String("pool")是在堆中分配,但new的操作要等到运行时才能执行,编译期并不会执行new操作,而编译器只是把字面量"pool"放入常量池中。运行时执行new操作会重新在堆中创建对象,并将引用 newStrtest指向这个对象。即测试四创建了两个对象,一个在常量池中,一个在堆中。下面这代码输出结果为false,可以证明这一点。

  String s1 = "hey";
  String s2 = new String("hey");
  System.out.println(s1==s2);//==比较的是引用,s1指向常量池,s2指向堆中,引用指向不同地址,因此输出false



再看第二种:[size=small]也有可能将运行期间的常量放入常量池
  比如
string.intern()
会检查常量池中是否存在string则返回池里的字符串引用;如果不存在则将string加入到常量池再返回其引用。这样做可以避免在堆中不断的创建字符串对象,起到节省空间的作用。
测试五(下面这段代码来自博客http://txy821.iteye.com/blog/760957)[/size]
  String str1 = "a"; 
  String str2 = "bc"; 
  String str3 = "a"+"bc"; 
  String str4 = str1+str2; 
   
  System.out.println(str3==str4); 
  str4 = (str1+str2).intern(); 
  System.out.println(str3==str4); 

  输出结果为false,true ‘测试三’中说过:编译器不会优化包含引用的运算,str4会在运行期,在堆中分配内存,所以第一个输出为false;而经过
str4 = (str1+str2).intern();

s4指向了常量池中的"abc"所以第二个输出为true。这样就可以证明上面提到的intern()的作用。
 
  最后在JDK源码String.intern()方法的注释中有这样一段话,"A pool of strings, initially empty, is maintained privately by the class {@code String}."
  说"有一个字符串池,初始为空,由String类私有的维护"。但注释中并没有说这个字符串池位于JVM内存分区的哪一个部分。是在方法区?堆区?这个困扰了我很长时间。查资料看到有人说位于堆中,但如果这样的话将会和方法区中常量池中的数据大量重复。而且网上的资料看到很多人都在说"字符串池"怎样怎样,但JVM的内存划分中并没有这样一块区域。
  所以我把"字符串池"理解成"常量池中字符串的集合"

  以上,如有错误,请指正



本页内容版权归属为原作者,如有侵犯您的权益,请通知我们删除。

btrace跟踪组数创建 - 2016-09-19 14:09:44

之前有人问我怎么用btrace跟踪数组的创建,这里记录一下。 需要靠Kind.NEWARRAY,比如要跟踪int数组的创建可以这么写 @BTracepublic class BtraceCreateArray { @OnMethod(clazz = "/.*/", method = "/.*/", location = @Location(value = Kind.NEWARRAY, clazz = "int") ) public static void findCreateIntArray() { pri

操作json - 2016-09-19 14:09:07

总是记不住一些零碎的知识点,这次开个专栏来记录,不定期更新: 1:json格式互转 1.1 :model转换json JSONObject jsonObject = JSONObject.fromObject(model);

解析数据存储MySQL - 2016-09-18 14:09:05

为了适应不同项目对不同感兴趣属性的解析存储,数据存储结构采用纵向的属性列表方式,即一个url页面多个属性存储多条记录方式,并且按照text,html,data,num几大典型类型分别对应存储。 创建UTF-8字符集的nutch数据库,并执行表初始化脚本,参考DDL: CREATE TABLE `crawl_data` ( `url` varchar(255) NOT NULL, `code` varchar(255) NOT NULL, `name` varchar(255) DEFAULT NULL,
一、定义:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验、转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。     与需要在编译时进行连接工作的语言不同,在Java语言里面,类型的加载、连接和初始化过程都是在程序运行期间完成的,这种策略虽然会令类加载时稍微增加一些性能开销,但是会为Java应用程序提供高度的灵活性,Java里天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接这个特点实现的。 二、类加载的时机     类从被加载到虚拟机内存中

java播放器 - 2016-09-18 14:09:03

最近写了一段java播放器代码 /* dkplus专业搜集和编写实用电脑软件教程,搜集各种软件资源和计算机周边(java网络编程,seo网站优化,web开发,lnmp,java网络编程,毕业论文设计),独立制作视频和ppt和音频微信公众号,点击进入 dkplus官方博客http://dkplus.iteye.com 微信搜索dkplus关注公众号可获取海量计算机周边资源。 */ package simpleaudioplayer; import javax.media.*;import java.io.I

Servlet之JSP_01概述 - 2016-09-17 18:09:08

一、什么是JSP JSP (Java Server Pages) 提供一种简便、快速的方式以生成动态的(dynamic)网页内容。 JSP运行原理 JSP 是 Servlet 的模板文件。 JSP最终由 Web 容器解析生成 Servlet 类( .java 文件),并编译成为 .class 文件,最后执行。 植入 JAVA 代码 可以告诉解析器,JSP 模板中的哪一部分是原生的 JAVA 代码,不需要解析。 在JSP中使用 % % 嵌入 JAVA 代码。 被 web 容器基于 JSP 文件而解析生成的
最近有遇到一个问题就是接口放提供的接口密文为PHP的sha256sum加密的内容 在网上找了半天没找到java相应的加密方式 最后迫不得已使用程序执行linux命令来加密 echo -n '123456bzGI9IZAaheT8LtAvhlYNnpDgwuy4hvw' | sha256sum | xxd -r -p | base64 -w0 java程序为: public static String getSHA256Value(String password){ String result = ""; I

聊天室java - 2016-09-17 14:09:07

最近写了一段聊天室java代码 /* dkplus专业搜集和编写实用电脑软件教程,搜集各种软件资源和计算机周边(java网络编程,seo网站优化,web开发,lnmp,java网络编程,毕业论文设计),独立制作视频和ppt和音频微信公众号,点击进入 dkplus官方博客http://dkplus.iteye.com 微信搜索dkplus关注公众号可获取海量计算机周边资源。 */ package com.server;import javax.swing.JButton;import javax.swing

Servlet之JSP概述 - 2016-09-16 14:09:06

一、什么是JSP JSP (Java Server Pages) 提供一种简便、快速的方式以生成动态的(dynamic)网页内容。 JSP运行原理 JSP 是 Servlet 的模板文件。 JSP最终由 Web 容器解析生成 Servlet 类( .java 文件),并编译成为 .class 文件,最后执行。 植入 JAVA 代码 可以告诉解析器,JSP 模板中的哪一部分是原生的 JAVA 代码,不需要解析。 在JSP中使用 % % 嵌入 JAVA 代码。 被 web 容器基于 JSP 文件而解析生成的
    最近项目遇到一个问题     要求项目对外提供的接口要保证每秒接受报文的能力达到  40个/秒(项目架构用的spring mvc),     而目前我这个接口不做任何操作,接受请求后直接返回,也才70个/秒的样子,如果收到报文做一次存储处理的话 就只有30个/秒的样子,求教下哪位有什么好的优化方案,可以从哪些方面做优化