`

Java对String字符串对象的创建,管理和“+”运算符的实现

    博客分类:
  • Java
阅读更多
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章节.


关于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 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)) + " " );  //lo在runtime会创建一个新的对象
                    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中.(编译时会直接优化成"aaaa",如果String Pool 中没有"aaaa",就用""号创建一个String,直接放到Pool中,比如:String t = "a"+ "b" +"c"; 会优化成"abc",然后放入Pool中;又比如String s = "x"+"y"+ref;在编译时有部分的优化:"xy",而ref + "x" +"y"就不会有部分的优化,"+"从左到右执行,ref是变量,编译时期无法确定)

4 .使用包含变量的字符串连接符如 " aa " + s1创建的对象是运行期才创建的,存储在heap中.

  (根据java api文档中String类所讲,会在内部使用stringbuffer及其append方法来实现连接,然后执行toString(),这样就会在运行时又创建一个新对象)



还有几个经常考的面试题:

1 .
String s1 = new String( " s1 " ) ;
String s2 = new String( " s1 " ) ;

上面创建了几个String对象 ?
答案:3个 ,编译期Constant Pool中创建1个,运行期heap中创建2个.
分享到:
评论

相关推荐

    java 创建字符串类

    Java提供了两种主要的方式来创建字符串:通过`String`类的构造方法和使用`StringBuilder`或`StringBuffer`类。以下是对这些知识点的详细解释: 1. **String类**: - **不可变性**:Java中的`String`对象是不可变的...

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

    在Java编程语言中,字符串(String)是一个非常基础且重要的数据类型。它被广泛用于存储文本信息,而关于字符串创建的理解,以及"equals()"方法和...在实际开发中,我们应该根据具体情况选择合适的字符串创建和比较方式。

    java中的字符串处理

    2. **字符串文字**:在Java中,可以直接使用字符串文字来创建`String`对象,例如: ```java String s = "abc"; System.out.println(s.length()); // 输出 3 ``` 3. **字符串连接**:Java支持使用`+`运算符连接...

    Java中的字符串相关处理

    不同于其他编程语言将字符串视为字符数组,Java将字符串视为`String`类型对象,这一设计使得字符串处理更加高效和安全。本文将深入探讨Java中字符串处理的相关知识点,包括`String`类型的特点、构造方法、字符串操作...

    java 创建字符串缓存类

    这是因为Java中的字符串是不可变的,每次对字符串进行修改都会生成一个新的对象,这可能会导致内存消耗增加和性能下降。为了解决这个问题,我们可以自定义一个字符串缓冲类来存储和复用字符串,以提高效率。 首先,...

    java 数组和字符串

    在顾客消费管理系统的设计中,不仅展示了如何创建和引用数组,还深入实践了对象数组的使用,以及通过循环和条件语句来实现对象数组的初始化和数据的动态管理。 #### 总结与反思 本次实验通过实际操作,加深了对...

    java中常用字符串方法总结

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

    Java基础之字符串及String

    总的来说,理解和熟练掌握Java中的字符串操作是成为Java程序员的基础,包括创建、比较、拼接以及字符串的内存管理,这些都是编写高效且无错误的Java代码的关键。在实际开发中,根据具体需求选择合适的字符串处理方法...

    JAVA 字符串 操作

    在Java编程语言中,字符串(String)是一个非常基础且重要的数据类型。它被广泛用于处理文本信息,例如用户输入、文件内容、网络数据等。本文将深入探讨Java中的字符串操作,包括创建、比较、拼接、查找与替换、分割...

    java实验-字符串.docx

    例如,当使用"+"运算符连接两个字符串时,实际上是创建了一个新的字符串对象。这种操作在频繁的字符串拼接中会降低效率,因为每次都会创建新的对象。而StringBuffer类是可变的,可以使用`append()`方法添加内容,而...

    java字符串实验题目

    这时,StringBuilder和StringBuffer类就派上用场了,它们提供了可变的字符串操作,适合在循环中进行字符串拼接,性能优于使用"+"运算符。 Java异常处理也是编程中的重要组成部分。在处理字符串相关的问题时,可能会...

    Java 字符串常用方法

    - `new String()`: 使用此构造函数创建一个新的字符串对象,可以传入字符数组或另一个字符串作为参数。 - `""`: 空字符串字面量,表示没有字符的字符串。 2. **获取字符串信息** - `length()`: 返回字符串的长度...

    String 字符串讲解

    - 当需要频繁修改字符串时,应考虑使用`StringBuilder`或`StringBuffer`,这两个类提供可变的字符串,避免每次修改时创建新的`String`对象。 理解并熟练运用这些`String`类的方法对于编写高效的Java代码至关重要,...

    Java SE编程入门教程 String字符串(共27页).pptx

    Java SE编程入门涉及众多基础知识,其中包括对字符串(String)的深入理解和使用。字符串在Java中扮演着重要的角色,因为它们在日常编程中几乎无处不在,无论是处理用户输入、读写文件还是进行网络通信。以下是对Java ...

    java String类的实现

    - `+` 运算符可以用于连接两个字符串,但背后会创建新的`String`对象。频繁使用可能导致性能问题。 - `StringBuilder`和`StringBuffer`类提供了更高效的字符串连接,特别是处理大量字符串拼接时,它们可以在内部进行...

    java作品,字符串

    由于字符串是不可变的,每次对字符串进行修改操作(如`substring()`、`replace()`等)都会生成新的字符串对象,不会改变原字符串。 五、二维数组 二维数组是数组的数组,可以理解为表格形式的数据存储。声明二维...

    java处理字符和字符串课件

    通过对Java中字符和字符串的处理方法的学习,我们可以更加灵活地进行数据处理。无论是简单的字符判断还是复杂的字符串操作,Java都提供了丰富的工具和支持。掌握这些基础知识对于提高编程效率和编写高质量的代码至关...

    Java 之 String 类型

    - 使用`+`运算符连接字符串,但频繁使用可能导致性能下降,因为它会创建新对象。对于大量拼接,建议使用`StringBuilder`或`StringBuffer`类。 5. **字符串与字符数组的转换** - `toCharArray()`:将字符串转换为...

    Java 字符串与文本相关实例源码

    在Java编程语言中,字符串(String)是至关重要的数据类型,用于处理文本信息。字符串是不可变的,这意味着一旦创建,就不能更改其内容。本实例源码集主要关注Java中的字符串和文本处理,提供了多种实际应用的示例,...

    Java第6章 字符串 含源代码

    在大量字符串操作时,使用`StringBuilder`或`StringBuffer`(线程安全)代替`+`运算符,以减少不必要的对象创建和垃圾回收。 源代码通常会涵盖以上知识点的应用,包括字符串的创建、操作、比较以及在实际问题中的...

Global site tag (gtag.js) - Google Analytics