`

String类总结

 
阅读更多

String类是Java中很重要的一个类,在此总结一下这个类的特别之处。
下面的相关资料翻译自《java语言规范》(第三版)和《java虚拟机规范》(第二版),有的直接摘引了原文。下面的代码都是用SUN jdk1.6 javac来编译。
1.String literal,这里将它翻译为字面常量,它由双引号包围的0个或多个字符组成,比如"abc","Hello World"等等。
一个String字面常量总是引用相同的String实例,比如"abc","abc"两个常量引用的是同一个对象。
程序测试:
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字面常量表示对同一个String对象的引用。
2) 同一个包下,不同的类中的相同的String字面常量表示对同一个String对象的引用。
3) 不同包下,不同类中的相同String字面常量同样表示对同一个String对象的引用。
4) 通过常量表达式计算的String,计算在编译时进行,并将它作为String字面常量对待。
5) 通过连接操作得到的String(非常量表达式),连接操作是运行时进行的,会新创建对象,所以它们是不同的。
6) 显式的对一个计算得到的String调用intern操作,得到的结果是已经存在的相同内容的String字面常量。
补充说明:
1)像这样的问题,String str = "a"+"b"+"c"+"d"; 运行这条语句会产生几个String对象?1个。
参考上面第5条,通过常量表达式得到的String 是编译时计算的,因此执行这句话时只有"abcd"着一个String对象存在。
常量表达是的定义可以参考java语言规范。
另例: final String str1 = "a"; String str2 = str1+"b";
执行第二句话会有几个String对象产生?1个。
因为str1是常量,所以str1+"b"也是常量表达式,在编译时计算。
遇到这种问题时,不要说它依赖于具体的编译器或者虚拟机实现,因为这就是规范里有的。
一般的说,java的编译器实现应该遵守《java语言规范》,而java虚拟机实现应该遵守《java虚拟机规范》。
2)不要这样使用字符串: String str = new String("abc");
参考文档中的说明: String public String(String original) 初始化一个新创建的 String 对象,使其表示一个与参数相同的字符序列;
换句话说,新创建的字符串是该参数字符串的副本。
由于 String 是不可变的,所以无需使用此构造方法,除非需要 original 的显式副本。
参数: original - 一个 String。 注意:无需使用此构造方法!!!
3)单独的说明第6点: String str = new String("abc"); str = str.intern();
当调用 intern 方法时,如果池已经包含一个等于此 String 对象的字符串(用 equals(Object) 方法确定),则返回池中的字符串引用。
否则,将此 String 对象添加到池中,并返回此 String 对象的引用。
很明显,在这个例子中"abc"引用的对象已经在字符串池中了,再调用intern返回的是已经存在池中内容为"abc"的字符换对象的引用。
在上面的例子中也说明了这个问题。

2. String类的实例表示表示Unicode字符序列。
String字面常量是指向String实例的引用。(字面常量是“引用”!)
3.String转换 对于基本类型先转换为引用类型;引用类型调用toString()方法得到String,如果该引用类型为null,转换得到的字符串为"null"。
4. String链接操作“+” 如果“+”操作的结果不是编译期常量,将会隐式创建一个新的对象。
为了提高性能,具体的实现可以采用StringBuffer,StringBuilder类对多个部分进行连接,最后再转换为String,从而避免生成再丢弃中间的String对象。
为了达到共享实例的目的,编译期常量总是“interned”的。
例子: String a = "hello "; String b = a+1+2+"world!";
反汇编结果: 0: ldc #2; //String hello 2: astore_1 3: new #3; //class java/lang/StringBuilder 6: dup 7: invokespecial #4; //Method java/lang/StringBuilder." <init>":()V 10: aload_1 11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 14: iconst_1 15: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 18: iconst_2 19: invokevirtual #6; //Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder; 22: ldc #7; //String world! 24: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 27: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 30: astore_2

实际就是 String b = new StringBuilder().append(a).append(1).append(2).append("world").toString();
这里就使用StringBuilder来避免中间临时String对象的产生而导致性能下降。
补充例子,下面的两个例子主要是对编译时常量做一个说明:
1) String c = "c"; String str = "a"+"b"+c; 和
2) String c = "c"; String str = c+"a"+"b";
1)中,str="a"+"b"+c;编译器分析是会把"a"+"b"作为编译时常量,生成字面常量"ab",所以实际执行这句话时,链接的是"ab"和c。
实际相当于执行了 String str = new StringBuilder().append("ab").append(c).toString();
2)中,String str = c+"a"+"b"; 编译器分析到c为变量,后面的"a"+"b"就不会作为编译时常量来运算了。
实际运行时相当于执行 String str = new StringBuilder().append(c).append("a").append("b").toString();
5.String对象的创建:
1) 包含String字面常量的类或者接口在加载时创建表示该字面常量的String对象。
以下两种情况下不会创建新String对象。
a) 一个相同的字面常量已经出现过。
b) 一个相同内容的字符串已经调用了intern操作(比如经过运算产生的字符串调用intern的情形)。
2) 非常量表达式的字符串连接操作有时会产生表示结果的String对象。
3) String字面常量来自类或接口的二进制表示中(也就是class文件中)的CONSTANT_String_info 结构。
CONSTANT_String_info结构给出了构成字符串字面常量的Unicode字符序列。
4) 为了生成字符串字面常量,java虚拟机检查 CONSTANT_String_info结构给出的字符序列:
a) 如果与CONSTANT_String_info结构中给出的字符换内容相同的串实例已经调用过String.intern,得到的字符串字面常量就来自该串的同一实例。
b) 否则,根据CONSTANT_String_info 中的字符序列创建一个新的字符串实例,然后调用intern方法。
例子:一个SCJP题目

11. public String makinStrings() {

12. String s = “Fred”;

13. s = s + “47”;

14. s = s.substring(2, 5);

15. s = s.toUpperCase();

16. return s.toString();

17. }

How many String objects will be created when this method is invoked? 答案是3个。
上面已经说明,"Fred","47"是字符串字面常量,它们在在类加载时创建的。这里题目问,方法调用时()有多少个String对象被创建,两个字面常量自然不包括在内。
3个是:"Fred47","ed4","ED4"。
6.String与基本类型的包装类比较 相同点,它们都是不变类,使用"=="判断时可能会有类似的性质。 在java 5之后,java增加了自动装箱和拆箱功能。

因此,就有了这样的性质: Integer i = 5; Integer j = 5; System.out.println(i == j); 结果:true.

这表面上看来是和String相同点,但其实现是极为不同的。这里作为一个不同点来介绍。
众所周知,自动装箱是这样实现的: Integer i = 5;

相当于 Integer i = Integer.valueOf(5);//注意不是new Integer(5),

这就无法满足java语言规范中的约定了,约定见本文最后

而在Integer中,静态的创建了表示从-128~+127之间数据的Integer对象,这个范围之内的数进行装箱操作,只要返回相应的对象即可。因此 Integer i = 5; Integer j = 5; 我们得到的是同一个对象。这是通过类库的设计来实现的。

而String的共享是通过java虚拟机的直接支持来实现的,这是它们本质的不同。

分享到:
评论

相关推荐

    java基础String类选择题练习题

    根据提供的信息,我们可以总结出这份Java基础String类选择题练习题主要聚焦于String及StringBuffer类的使用。尽管具体的题目内容未给出,但从所展示的信息中可以推断出该练习题集涵盖了以下几方面的知识点: ### 一...

    简单的string类

    总结起来,`std::string`是C++中处理字符串的重要工具,它提供了丰富的功能和便捷的API,使得字符串操作变得简单而高效。理解并熟练使用`std::string`,对提升编程能力大有裨益。在学习和实践中,我们应该不断探索其...

    String类方法总结

    标题:“String类方法总结” 描述:“string类方法总结,由毕姥爷精心提炼,被誉为学习String类的必读经典。” **知识点详述:** 在Java编程语言中,`String`类是一个极其重要的类,用于处理文本数据。由于其不可...

    标准C++中的string类的用法总结

    ### 标准C++中的`string`类的用法总结 在C++编程语言中,`string`类是处理字符串的利器,它提供了丰富的功能,远远超过了传统的C风格字符串(即`char*`)。`string`类封装了字符串操作的所有细节,使得字符串处理变...

    string类的构造方法_String类重要吗_C++_STL_string_

    标题中的“string类的构造方法”揭示了我们要探讨的核心内容——如何初始化和创建`std::string`对象。`std::string`类不仅在日常编程中频繁使用,而且在很多高级功能如正则表达式、文本处理等方面都有重要应用,因此...

    JAVA实验报告四(实现String类).doc

    Java 实验报告四(实现 String 类) 在本实验报告中,我们将实现 Java 中的 String 类,并了解其实现原理。 String 类是 Java 中一个非常重要的类,它提供了字符串操作的各种方法。在这里,我们将基于 ArrayList ...

    string 类及所有的方法(c++)

    总结来说,C++的string类提供了强大的字符串处理功能,其便利性体现在内存管理自动化、丰富的操作函数以及与C字符串的兼容性。在编程中,我们应该优先考虑使用string类来处理字符串,以提高代码的可读性和安全性。...

    String类常见功能

    ### String类常见功能详解 #### 一、String类概述 String 类在 Java 中是一个非常重要的类,用于表示不可变的字符序列。简单来说,就是它代表了一串字符组成的字符串,并且一旦创建,其内容不能被修改。这在 Java ...

    C++重写String类

    一、为什么要重写String类? 1. **定制功能**:标准库的`std::string`可能不满足某些特定需求,如特定的内存管理策略、额外的成员函数或操作符重载。 2. **教学目的**:通过实现自己的字符串类,可以更好地理解字符...

    C++ string 类 用法总结

    C++中的`std::string`类是处理字符串的利器,它提供了丰富的成员函数和操作,使得在C++中处理文本变得高效且易于管理。这里我们将深入探讨`std::string`的一些主要特性和用法。 首先,`std::string`类的构造函数...

    Java-String类的常用方法总结.pdf

    在这个总结中,我们将深入探讨String类的一些核心特性和方法。 首先,String类位于`java.lang`包中,这意味着它对所有Java程序都是自动导入的,无需额外引用。String类被声明为final,这意味着我们无法创建其子类,...

    C++中的string类

    ### C++中的string类 #### 引言 在C++编程语言中,`string`类是一种非常实用且功能强大的工具,它为处理文本数据提供了极大的便利。与传统的`char *`字符串相比,`string`类提供了更多的内置方法来简化字符串的...

    Java中String类中的常用方法.TXT

    简单总结可以下Java中String类中的常用方法

    自己动手编写string类

    根据提供的文件信息,我们可以从中提取出以下知识点,有关C++中如何实现自定义的string类(MyString),以及相关的知识点: 1. **C++标准库string类**: - 标准库中的string实际上是一个typedef,它基于basic_...

    简单的string类的模拟

    #### 一、C++中的String类设计与实现 在本案例中,我们通过自定义一个`String`类来探讨如何在C++中实现字符串类的基本功能,包括构造函数、析构函数、重载运算符以及成员函数等。 #### 二、构造函数与析构函数 1....

    自己封装C++的String类

    这是我自己写的一个String类,当然也结合了网上好多文档,最终总结的。这个类在小项目中完全可以恰到好处了,但是如果是大型项目,请自己再修改下,或者添加其他的类。

    string类的各种方法的使用

    根据给定文件的信息,我们可以总结出关于C++中`string`类的各种方法的详细知识点。 ### 1. 字符串长度 在C++中,获取一个`string`对象的长度非常简单,只需要调用成员函数`length()`即可。例如: ```cpp string ...

    自定义string类

    ### 自定义String类详解 #### 一、引言 在软件开发过程中,字符串处理是非常常见的需求之一。标准库中的`std::string`类为开发者提供了高效且易用的字符串操作功能,但在某些特定场景下,可能需要实现一个自定义的...

    深入探讨Java中的String类.pdf

    Java 中的 String 类 Java 中的 String 类是 Java 编程语言中最基本的数据类型之一。String 类是 Java 的一个 final 类,无法被继承。它是 Java 中用于表示字符串的类。Java 中的 String 类有很多特点和用途,本文...

Global site tag (gtag.js) - Google Analytics