`
tianlihu
  • 浏览: 314001 次
  • 性别: Icon_minigender_1
  • 来自: 石家庄
社区版块
存档分类
最新评论

java对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
String s1 = "sss111";
//此语句同上
String s2 = "sss111";
System.out.println(s1 == s2); //结果为true


例2
String s1 = new String("sss111");
String s2 = "sss111";
System.out.println(s1 == s2); //结果为false


例3
String s1 = new String("sss111");
s1 = s1.intern();
String s2 = "sss111";
System.out.println(s1 == s2);


例4
String s1 = new String("111");
String s2 = "sss111";
String s3 = "sss" + "111";
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中;
  5.使用"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"




分享到:
评论

相关推荐

    java的String字符串补0

    ### Java的String字符串补0技术解析 #### 一、引言 在Java编程中,对字符串进行特定格式化的处理是一项常见的需求。其中,“补0”操作尤其常见于日期时间格式化、编号序列化等场景中。例如,在处理数据库查询结果时...

    Java程序设计基础:创建String字符串.pptx

    掌握String字符串对象的创建 掌握字符串对象的输入与输出 一般程序需要处理大量文本数据Java语言的文本数据被保存为字符或字符串类型。 若干个字符在计算机里面如何存储? 如何引用呢? 引入 例如 ...

    java 创建字符串类

    以上就是关于"Java创建字符串类"这一主题的详细阐述,包括`String`类的基本使用、可变字符串类`StringBuilder`和`StringBuffer`,以及相关的操作方法。理解并熟练运用这些知识点对于编写高效且功能丰富的Java程序至...

    java反射机制 字符串——java对象

    这一过程涉及到了对`java.lang.reflect`包中类的使用,如`Class.forName()`用于获取类的Class对象,`Constructor.newInstance()`用于创建对象,以及`Method.invoke()`用于调用方法。 总的来说,Java反射机制和字符...

    Java中颜色的String和Color对象之间的互相转换

    在将字符串形式的颜色转换为 Color 对象时,我们可以使用 `Integer.parseInt` 方法将十六进制字符串解析为整数,然后根据该整数创建颜色对象。例如: ```java public static Color String2Color(String str) { int ...

    java解析xml字符串

    1. **初始化XML源**:首先,将XML字符串转化为`StringReader`对象,这是为了将字符串转换为可以被SAXBuilder读取的形式。接着,使用`InputSource`封装`StringReader`,以便SAXBuilder能够正确识别并解析XML数据。 2...

    JAVA日期与字符串的转换

    在Java编程中,经常需要将日期对象转化为字符串形式以便于存储或显示,或者反过来将字符串转化成日期对象来进行日期计算等操作。本文将详细介绍如何在Java中实现这两种转换。 #### 一、将一个Date类型的变量转换为...

    Java中Json字符串直接转换为对象的方法(包括多层List集合)

    本文将详细介绍如何将JSON字符串直接转换为Java对象,特别是涉及到多层List集合的情况。在本例中,我们将使用`net.sf.json.JSONObject`类来实现这一功能。 首先,确保你的项目中已经引入了必要的库。在使用`...

    java 创建字符串缓存类

    通过使用`StringBuffer`或`StringBuilder`以及自定义缓存类,我们可以有效地管理字符串对象,避免不必要的内存分配。在实际项目中,可以根据需求调整缓存大小、选择合适的线程安全机制,以达到最佳的性能和资源利用...

    Java String 字符串创建理解 equels和\"==\" 差异

    这种方式创建的字符串会存储在常量池中,如果常量池中已有相同的字符串,那么会复用该字符串对象,不会创建新的。 2. **使用new关键字**:`String str = new String("Hello, World!");` 使用new关键字创建的字符...

    java中的字符串处理

    4. **复制字符串**:`String(String strObj)` 可以通过已有的字符串对象来创建新的字符串对象,例如: ```java String s1 = new String("java"); String s2 = new String(s1); System.out.println(s1.equals(s2)...

    Java中的字符串相关处理

    `String`提供了多种构造方法,以便开发者根据不同的需求创建字符串对象: 1. **无参数构造器**:`String s = new String();` 创建一个空白字符串。 2. **字符数组构造器**:`String s = new String(char[] chars);`...

    Java设置String字符串编码方法详解

    本文将深入探讨Java中设置String字符串编码的方法,帮助开发者更好地理解和使用这些功能。 首先,我们需要理解什么是字符编码。字符编码是将字符(如字母、数字和符号)与数字或二进制值关联的系统,例如ASCII、...

    【Java编程教程】详解Java String字符串.pdf

    2. 使用`new`关键字:如`new String("Hello")`,这会在堆内存中创建新的字符串对象,即使字符串的内容在常量池中已经存在。 Java字符串是不可变的,这意味着一旦创建,就不能改变其内容。如果需要改变字符串,必须...

    java验证字符串是否符合json格式

    因此,确保你的代码能够有效且安全地处理这些字符串是非常重要的,这包括对字符串进行预处理、错误处理以及验证。在处理JSON数据时,还应考虑性能和资源消耗,避免不必要的对象创建和解析。通过合理地设计和使用JSON...

    Java基础之字符串及String

    这种特性确保了字符串对象的线程安全性,但同时也意味着每次修改都会创建一个新的`String`对象。 字符串的创建主要有两种方式: 1. **通过字面量赋值创建**: ```java String s1 = "laofu"; ``` 这种方式创建...

    java 数组和字符串

    本次实验旨在深化理解Java中的数组与字符串操作,聚焦于`String`类与`StringBuffer`类的掌握,包括它们的常用方法、相等性判断的不同方式、数组的创建及引用机制,以及`Arrays`类的静态方法应用。实验通过具体的编程...

    java字符串处理取出括号内的字符串

    首先,我们要明白Java中的字符串是`String`类的对象,它提供了丰富的API用于字符串的处理。例如,我们可以使用`substring()`方法来截取字符串的一部分,但这并不适用于提取括号内的内容,因为我们需要识别开括号和闭...

    java中常用字符串方法总结

    在Java中,有多种方式来创建字符串对象,如通过`new`关键字、使用`String`字面量或者通过`StringBuffer/StringBuilder`类。例如: ```java String str1 = new String("Hello"); // 使用new关键字 String str2 = ...

    详解Java String字符串获取每一个字符及常用方法

    "Java String字符串获取每一个字符及常用方法" 本文主要介绍了Java String字符串获取每一个字符及常用方法,涵盖了字符串的基本操作、获取每一个字符的方法、substring方法、trim方法、charAt方法等,并通过实例...

Global site tag (gtag.js) - Google Analytics