- 浏览: 303284 次
- 性别:
- 来自: 北京
文章分类
最新评论
-
stamina:
请问这个装在svn的客户端吗?我试了,发现命令“ava -ja ...
statsvn 统计svn代码量 -
在世界的中心呼喚愛:
不错,找到方法!!
利用Jackson对Object,Map,List,数组,枚举,日期类等转化为json -
lg5414:
已经不错了
OutOfMemoryError: unable to create new native thread -
liubey:
这个年代的项目编码还有用latin1的,是个坑啊 蛤蛤
ubuntu下maven构建工程中文乱码 -
wp0615032:
因为那个timestamp是一个乐观锁,每次更新时这个填要带上 ...
hibernate异常 org.hibernate.StaleObjectStateException: Row was updated or deleted
深入研究java对String字符串对象的创建以及管理
(2008-9-27 bbh)
新手初学,不对的地方大家多多指教~
经常看到很多人讨论java中关于String的问题,我也就有点兴趣了,鉴于网上很多人写的都差别很大,
同样的问题都是不同的说法,我很迷糊,花了一晚上读了Java Virtual Machine Specification和
The Java Language Specification的一些章节,做了很多试验,总结了一下关于String的内容,还
有很多内容我也不确定,在下面也都提出来了,希望高手能指正.
Constant Pool常量池的概念:
在讲到String的一些特殊情况时,总会提到String Pool或者Constant Pool,但是我想很多人都不太
明白Constant Pool到底是个怎么样的东西,运行的时候存储在哪里,所以在这里先说一下Constant Pool的内容.
String Pool是对应于在Constant Pool中存储String常量的区域.习惯称为String Pool,也有人称为
String Constant Pool.好像没有正式的命名??
在java编译好的class文件中,有个区域称为Constant Pool,他是一个由数组组成的表,类型
为cp_info constant_pool[],用来存储程序中使用的各种常量,包括Class/String/Integer等各
种基本Java数据类型,详情参见The Java Virtual Machine Specification 4.4章节.
对于Constant Pool,表的基本通用结构为:
cp_info {
u1 tag;
u1 info[];
}
tag是一个数字,用来表示存储的常量的类型,例如8表示String类型,5表示Long类型,info[]根据
类型码tag的不同会发生相应变化.
对于String类型,表的结构为:
CONSTANT_String_info {
u1 tag;
u2 string_index;
}
tag固定为8,string_index是字符串内容信息,类型为:
CONSTANT_Utf8_info {
u1 tag;
u2 length;
u1 bytes[length];
}
tag固定为1,length为字符串的长度,bytes[length]为字符串的内容.
(以下代码在jdk6中编译)
为了详细理解Constant Pool的结构,我们参看一些代码:
String s1 = "sss111";
String s2 = "sss222";
System.out.println(s1 + " " + s2);
由于"sss111"和"sss222"都是字符串常量,在编译期就已经创建好了存储在class文件中.
在编译后的class文件中会存在这2个常量的对应表示:
08 00 11 01 00 06 73 73 73 31 31 31 08 00 13 01 ; ......sss111....
00 06 73 73 73 32 32 32 ; ..sss222
根据上面说的String常量结构,我们分析一下
开始的08为CONSTANT_String_info结构中的tag,而11应该是它的相对引用,01为
CONSTANT_Utf8_info的tag,06为对应字符串的长度,73 73 73 31 31 31为字符串对
应的编码,接着分析,会发现后面的是对应"sss222"的存储结构.
经过上面分析,我们知道了11和13是两个字符串的相对引用,就可以修改class文件
来修改打印的内容,把class文件中的
00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 12 4D
改成
00 6E 00 04 00 03 00 00 00 24 12 10 4C 12 10 4D
程序就会输出sss111 sss111,而不是和原程序一样输出sss111 sss222,因为我
们把对"sss222"的相对引用12改成了对"sss111"的相对引用10.
------------分割线
public class Test {
public static void main(String[] args) {
String s1 = "sss111";
String s2 = "sss111";
}
}
在上面程序中存在2个相同的常量"sss111",对于n个值相同的String常量,在Constant Pool中
只会创建一个,所以在编译好的class文件中,我们只能找到一个对"sss111"的表示:
000000abh: 08 00 11 01 00 06 73 73 73 31 31 31 ; ......sss111
在程序执行的时候,Constant Pool会储存在Method Area,而不是heap中.
另外,对于""内容为空的字符串常量,会创建一个长度为0,内容为空的字符串放到Constant Pool中,
而且Constant Pool在运行期是可以动态扩展的.
关于String类的说明
1.String使用private final char value[]来实现字符串的存储,也就是说String对象创建之后,就不能
再修改此对象中存储的字符串内容,就是因为如此,才说String类型是不可变的(immutable).
2.String类有一个特殊的创建方法,就是使用""双引号来创建.例如new String("i am")实际创建了2个
String对象,一个是"i am"通过""双引号创建的,另一个是通过new创建的.只不过他们创建的时期不同,
一个是编译期,一个是运行期!
3.java对String类型重载了+操作符,可以直接使用+对两个字符串进行连接.
4.运行期调用String类的intern()方法可以向String Pool中动态添加对象.
String的创建方法一般有如下几种
1.直接使用""引号创建.
2.使用new String()创建.
3.使用new String("someString")创建以及其他的一些重载构造函数创建.
4.使用重载的字符串连接操作符+创建.
例1
/*
* "sss111"是编译期常量,编译时已经能确定它的值,在编译
* 好的class文件中它已经在String Pool中了,此语句会在
* String Pool中查找等于"sss111"的字符串(用equals(Object)方法确定),
* 如果存在就把引用返回,付值给s1.不存在就会创建一个"sss111"放在
* String Pool中,然后把引用返回,付值给s1.
*
*/
String s1 = "sss111";
//此语句同上
String s2 = "sss111";
/*
* 由于String Pool只会维护一个值相同的String对象
* 上面2句得到的引用是String Pool中同一个对象,所以
* 他们引用相等
*/
System.out.println(s1 == s2); //结果为true
例2
/*
* 在java中,使用new关键字会创建一个新对象,在本例中,不管在
* String Pool中是否已经有值相同的对象,都会创建了一个新的
* String对象存储在heap中,然后把引用返回赋给s1.
* 本例中使用了String的public String(String original)构造函数.
*/
String s1 = new String("sss111");
/*
* 此句会按照例1中所述在String Pool中查找
*/
String s2 = "sss111";
/*
* 由于s1是new出的新对象,存储在heap中,s2指向的对象
* 存储在String Pool中,他们肯定不是同一个对象,只是
* 存储的字符串值相同,所以返回false.
*/
System.out.println(s1 == s2); //结果为false
例3
String s1 = new String("sss111");
/*
* 当调用intern方法时,如果String Pool中已经包含一个等于此String对象
* 的字符串(用 equals(Object)方法确定),则返回池中的字符串.否则,将此
* String对象添加到池中,并返回此String对象在String Pool中的引用.
*/
s1 = s1.intern();
String s2 = "sss111";
/*
* 由于执行了s1 = s1.intern(),会使s1指向String Pool中值为"sss111"
* 的字符串对象,s2也指向了同样的对象,所以结果为true
*/
System.out.println(s1 == s2);
例4
String s1 = new String("111");
String s2 = "sss111";
/*
* 由于进行连接的2个字符串都是常量,编译期就能确定连接后的值了,
* 编译器会进行优化直接把他们表示成"sss111"存储到String Pool中,
* 由于上边的s2="sss111"已经在String Pool中加入了"sss111",
* 此句会把s3指向和s2相同的对象,所以他们引用相同.此时仍然会创建出
* "sss"和"111"两个常量,存储到String Pool中.
修改为:
/*
* 由于进行连接的2个字符串都是常量,编译期就能确定连接后的值了,
* 编译器会进行优化直接把他们表示成"sss111"存储到String Pool中,
* 由于上边的s2="sss111"已经在String Pool中加入了"sss111",
* 此句会把s3指向和s2相同的对象,所以他们引用相同.此时"sss"和"111"
* 两个常量不会再创建.
*/
*/
String s3 = "sss" + "111";
/*
* 由于s1是个变量,在编译期不能确定它的值是多少,所以
* 会在执行的时候创建一个新的String对象存储到heap中,
* 然后赋值给s4.
*/
String s4 = "sss" + s1;
System.out.println(s2 == s3); //true
System.out.println(s2 == s4); //false
System.out.println(s2 == s4.intern()); //true
例5
这个是The Java Language Specification中3.10.5节的例子,有了上面的说明,这个应该不难理解了
package testPackage;
class Test {
public static void main(String[] args) {
String hello = "Hello", lo = "lo";
System.out.print((hello == "Hello") + " ");
System.out.print((Other.hello == hello) + " ");
System.out.print((other.Other.hello == hello) + " ");
System.out.print((hello == ("Hel"+"lo")) + " ");
System.out.print((hello == ("Hel"+lo)) + " ");
System.out.println(hello == ("Hel"+lo).intern());
}
}
class Other { static String hello = "Hello"; }
package other;
public class Other { static String hello = "Hello"; }
输出结果为true true true true false true,请自行分析!
结果上面分析,总结如下:
1.单独使用""引号创建的字符串都是常量,编译期就已经确定存储到String Pool中.
2.使用new String("")创建的对象会存储到heap中,是运行期新创建的.
3.使用只包含常量的字符串连接符如"aa" + "aa"创建的也是常量,编译期就能确定,已经确定存储到String Pool中.
4.使用包含变量的字符串连接符如"aa" + s1创建的对象是运行期才创建的,存储在heap中.
6.使用"aa" + s1以及new String("aa" + s1)形式创建的对象是否加入到String Pool中我不太确定,可能是必须
调用intern()方法才会加入,希望高手能回答 @_@
还有几个经常考的面试题:
1.
String s1 = new String("s1") ;
String s2 = new String("s1") ;
上面创建了几个String对象?
答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.
2.
String s1 = "s1";
String s2 = s1;
s2 = "s2";
s1指向的对象中的字符串是什么?
答案: "s1"
发表评论
-
test
2015-12-23 11:21 0test test test testtest te ... -
java.net.UnknownHostException
2013-11-22 16:22 0服务器上tomcat启动时,报如下错误: 15:2 ... -
OutOfMemoryError: unable to create new native thread
2013-11-20 15:49 3084当看到这个错误时,第一感觉是创建的线程太多了、 ... -
ibatis配置log4j输出sql
2013-06-04 11:53 0不输出httpclient请求头信息: log4j. ... -
命令行编译 运行java程序
2013-05-23 14:13 0lucene的demo代码,需要在命令行下运行,折腾了半会, ... -
GraphicsMagick和im4java按比例压缩图片
2013-04-22 19:26 83261.先安装libpng-1.6.2rc02.tar.gz( ... -
服务器上某应用cpu一直100%问题记录
2013-04-18 21:35 5059jstack 31066 |grep 'nid=79 ... -
jvisualvm远程监控tomcat
2013-11-20 14:02 1385在tomcat的catalina.sh中的JAVA_OPT ... -
计算byte表示的二进制数据中,1出现的次数
2011-11-29 12:55 1514无意中看到这个题目,开始想到的是把byte的二进制数据转为一个 ... -
eclipse下的gc.log记录
2011-07-06 08:06 1517eclipse下的gc.log记录: 6.784: [G ... -
利用Jackson对Object,Map,List,数组,枚举,日期类等转化为json
2011-05-18 22:43 50756利用Jackson中的ObjectMapper对象,转为对象为 ... -
设计模式 代理模式(静态代理)
2011-04-08 09:05 1233代理模式的作用:为其他对象提供代理以控制对这个对象的访问. ... -
alipay 电面记录
2011-04-06 21:10 14521. 网站压力测试 2.jvm 调优,jvm内存管理,垃圾收集 ... -
PermGen space 溢出 使用jstat查看 Permsize 占用情况 并设置 PermSize和MaxPermSize
2011-03-02 11:38 17747网站以前经常java.lang.OutOfMemoryErro ... -
Collection接口的remove和List接口的remove的差别
2011-02-25 21:00 1865刚看书上一段代码,觉得输出的结果有点奇怪,查看了jdk的api ... -
tomcat6 中get 和 post 表单提交时编码的差别
2011-01-13 22:30 4330相信搞java的朋友都 ... -
struts2 报错时不进入 指定的500页面的原因
2010-12-15 13:34 5011折腾好些天了,我们项目用的web框架是struts2,具体那 ... -
jquery请求 返回json格式数据
2010-07-26 15:03 1619这个问题应该是常识性问题,可我还是不是很明白。 在前台用jqu ... -
java ant maven windows下 环境变量
2010-07-13 10:37 1303要运行springside,安装ant,maven是必需的。 ... -
java 工程再次无法编译
2010-06-03 09:38 1251以前遇到这种工程无法编译的情况,无非删掉class文件,重启i ...
相关推荐
Java String 使用详解 Java String 使用详解是 Java 编程语言中最基础也是最重要的一部分,对于 Java 程序员来说,了解 String 类的使用方法是必不可少的。本文将详细介绍 Java String 的使用方法,包括 String ...
在Java编程语言中,`String`类是处理文本字符串的核心工具。它是一个不可变对象,意味着一旦创建,其内容就不能更改。这是因为`String`在Java中被实现为一个特殊的类,存储在一个连续的字符数组中,这个特性对于理解...
5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5.javaString类.zip5....
在JDK1.5中,String类增加了一个非常有用的静态函数format(String format, Objece... argues),可以将各类数据格式化为字符串并输出。其中format参数指定了输出的格式,是最复杂也是最难掌握的一点,而argues则是一...
在Java编程语言中,String类是处理文本字符串的核心类,而与各种进制字符之间的转换是常见的编程需求。本文将详细探讨Java中如何进行String与二进制、八进制、十进制以及十六进制之间的转换。 首先,我们要了解进制...
在Java编程中,String对象和Byte类型的转换是常见的操作,特别是在网络编程中,因为网络通信通常涉及字节流的处理。下面将详细讲解Java中如何进行这两种类型之间的转换,并探讨其在网络编程中的应用。 首先,让我们...
Java中的`String`类是编程中最常用的类之一,它在Java的`java.lang`包中,无需显式导入即可使用。`String`类代表不可变的字符序列,这意味着一旦创建了`String`对象,它的值就不能改变。这个特性使得`String`在处理...
Java中的String对象是编程中经常遇到的关键元素,它在各种场景下都有广泛的应用。下面将详细探讨Java String的十大常见问题及其解决方案。 1. **字符串比较:使用"=="还是equals()?** 在Java中,"=="运算符比较的...
在Java编程中,字符串(String)是非常常见且重要的数据类型。本文主要讨论了如何正确判断Java中的String对象是否为null、空值("")以及它们的地址是否相等。在处理字符串时,了解这些概念对于避免程序出错至关重要。...
日期转换例子,支持含各种语言的三个字母缩写...适用于数据导入数据库String类型中含英文缩写转换,网上普遍使用的String to Date 都不适用含Mon Jul 等缩写,对比API,可以实现任意格式的String 类型转换成Date类型
在Java编程语言中,String和StringBuilder是两个非常重要的类,它们在处理文本字符串时起着核心作用。了解这两个类的特点和使用场景对于提高程序性能至关重要。 首先,`String`类在Java中是不可变的,这意味着一旦...
Java String API 中常用的方法 Java String API 中提供了许多有用的方法来操作字符串,這些方法可以帮助开发者轻松地处理字符串操作。下面是 Java String API 中常用的方法: 一、获取 Java String API 中提供了...
这份"javaString总结共13页.pdf.zip"压缩包文件显然包含了关于Java字符串的深入讲解,覆盖了多个关键知识点。虽然没有提供具体的PDF内容,但我可以基于常见的Java String主题为你概述一些重要的概念。 1. **字符串...
在Java编程语言中,`String`和`StringBuffer`是用来处理文本字符串的两种不同类,它们各有特点并适用于不同的场景。理解它们之间的区别对于优化代码性能至关重要。 首先,`String`类代表的是不可变的字符串。这意味...
Java String 用法详解 字符串是 Java 中最重要的类,了解 String 的用法是 Java 开发者的必备知识。本文将从多个角度介绍 String 的用法,包括字符串的不可变性、字符串常量池、+号和 StringBuilder 等。 字符串的...
在Java编程中,经常需要处理JSON格式的数据,它是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器解析和生成。JSON格式通常用于前后端数据交互,因为其结构清晰,支持复杂的数据结构,如对象(Object)...
Java中的String类是用于表示和操作字符串的基本类,它在Java编程中扮演着至关重要的角色。String类的对象是不可变的,这意味着一旦创建了String对象,就不能改变其内容。这是因为字符串在Java中被视为常量,存储在...
### 有关Java String常用方法的总结 #### 一、String 类概述 `String`类是Java中最基础也是最重要的数据类型之一,在Java中被定义为一个不可变类(immutable class),这意味着一旦一个`String`对象创建之后,其...
"深入理解 Java String#intern() 内存模型" Java String#intern() 内存模型是 Java 语言中一个重要的概念,.string#intern() 方法是 Java 字符串常量池中一个重要的组件。字符串常量池是一个固定大小的 HashMap,桶...