(原创)深入研究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
-
-
- Strings1="sss111";
-
-
Strings2="sss111";
-
-
- System.out.println(s1==s2);
例2
-
-
- Strings1=newString("sss111");
-
-
- Strings2="sss111";
-
-
- System.out.println(s1==s2);
例3
-
Strings1=newString("sss111");
-
-
- s1=s1.intern();
-
- Strings2="sss111";
-
-
- System.out.println(s1==s2);
例4
-
Strings1=newString("111");
-
Strings2="sss111";
-
-
- Strings3="sss"+"111";
-
-
- Strings4="sss"+s1;
-
System.out.println(s2==s3);
-
System.out.println(s2==s4);
-
System.out.println(s2==s4.intern());
例5
这个是The Java Language Specification中3.10.5节的例子,有了上面的说明,这个应该不难理解了
-
packagetestPackage;
-
classTest{
-
publicstaticvoidmain(String[]args){
-
Stringhello="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());
- }
- }
-
classOther{staticStringhello="Hello";}
-
packageother;
-
publicclassOther{staticStringhello="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"
相关推荐
13. **字符串的不可变性**:由于字符串的不可变性,每次对字符串的操作都会创建一个新的字符串对象,因此在处理大量字符串时需要注意内存消耗。 14. **StringBuilder与StringBuffer**:如果需要频繁修改字符串,...
这个功能涉及到对字符串的解析、分割以及重新组合,是字符串操作的一个典型实例。 首先,让我们理解什么是字符串逆序。在一般情况下,字符串逆序是指将一个字符串中的字符顺序颠倒过来。例如,"Hello World"逆序后...
在Java编程语言中,`java.lang....通过深入研究源码,我们能更深入地理解Java内存管理以及如何优化字符串操作。在日常开发中,应充分利用`String`提供的功能,同时注意选择合适的字符串处理策略,以达到最佳性能。
`StringManipulation`这个项目显然专注于研究和实现Java中的字符串处理算法。下面将详细介绍Java中常见的字符串处理技术及其背后的原理。 一、字符串的创建与初始化 在Java中,字符串是对象,可以通过以下方式创建...
在Java中,我们可以使用SimpleDateFormat或DateTimeFormatter将日期型字符串转换为日期对象。例如: ```java import java.text.SimpleDateFormat; import java.util.Date; SimpleDateFormat formatter = new ...
而在像Java或Python这样的高级语言中,字符串是不可变对象,每次修改都会创建新的字符串实例。这种设计有其优点,例如提高了字符串操作的安全性,但也可能导致性能问题,因为频繁创建新对象会消耗更多的内存。 字符...
总结来说,“按byte截取字符串”是一项实用的技术,涉及到字符串编码、字节数组操作以及对Java语言特性的深入理解。在实际开发中,掌握这项技能对于处理与字节流相关的任务至关重要,尤其是在处理网络数据传输、文件...
在Java中,字符串是类`String`的对象,因此在词法分析时,需要识别出以双引号开始和结束的字符序列,并将其转换为对应的`String`对象。这个过程中,词法分析器还需要处理转义字符,如"\n"表示换行,"\t"表示制表符。...
Gson库的核心功能在于它能够将Java对象序列化为JSON字符串,同时也能将JSON字符串反序列化为相应的Java对象。在本资料包中,包含了Gson库的源码和jar文件,这将有助于我们深入理解和使用Gson库。 首先,我们来看...
此外,该项目可能还涵盖了如何处理无分隔符或分隔符连续的情况,以及如何在分割后对结果进行进一步处理,比如去除空字符串或者对子字符串进行排序。 总之,字符串分割是数据处理的基础技能,无论你是初学者还是经验...
本话题将深入探讨如何使用Java来统计一个字符串中包含的单词数量以及每个单词出现的次数。"chongfu.rar_Java字符串空格_单词统计_统计单词"这个标题暗示了我们将重点研究基于空格分隔的字符串进行单词统计的方法。 ...
在Java编程语言中,对字符串列表进行字母表顺序排列是一个常见的任务,这涉及到集合操作和比较算法的应用。本文将深入探讨如何使用Java实现这一功能,同时结合提供的资源,包括"下载及使用说明.txt"、"更多Java资料...
在实际开发中,很多编程语言都提供了一些内置的字符串工具类或模块,如Python的`str`类、JavaScript的`String`对象、C#的`System.Text.StringBuilder`等。这些工具类通常包含一系列静态方法,用于执行诸如格式化、...
在Java开发中,数据交换和持久化经常涉及对象与JSON字符串之间的转换。Google的Gson库提供了一种简单而强大的方式来实现这个功能。本文将深入探讨如何利用Gson库进行对象到JSON以及JSON到对象的转换,并分享一个示例...
"深入研究java.lang.Runtime类" java.lang.Runtime 类是 Java 语言中一个非常重要的类,它提供了访问当前 Java 应用程序的 Runtime 环境的能力。每个 Java 应用程序都有一个 Runtime 类实例,使应用程序能够与其...
本文将围绕“字符串查找”这一主题,深入探讨其概念、应用以及实现方法,并通过分析提供的代码片段来理解如何在Java中进行字符串查找。 ### 字符串查找的概念 字符串查找是指在给定的文本或字符串中搜索特定的字符...
本文将深入探讨C语言中如何利用字符数组来处理字符串,以及相关的初始化、赋值、长度判断等关键概念。 #### C语言中的字符串特点 首先明确一点,**C语言中并没有专门的字符串类型**。这与诸如C++、Java或VB等现代...
在IT行业中,日期字符串的截取与格式化是常见的任务,尤其在处理日志、数据分析或者用户界面展示时。这个话题涉及到编程语言...如果你对这个主题有更深入的研究,阅读相关博客、官方文档和源码都是提升技能的有效途径。
在这个Java项目中,可能会使用到`String`类的一些内置方法,如`length()`、`charAt()`以及`indexOf()`等,用于获取字符串长度、访问特定位置的字符以及查找子串的位置。同时,为了计算相似度,可能还使用了动态规划...
9. **String字符串的用法**:Java中的String是不可变对象,它有丰富的API供开发者进行字符串操作,如concatenation、substring、indexOf、replace等。此外,还会涉及String对象与StringBuilder/StringBuffer的区别。...