要理解 java中String的运作方式,必须明确一点:String是一个非可变类(immutable)。什么是非可变类呢?简单说来,非可变类的实例是不能被修改的,每个实例中包含的信息都必须在该实例创建的时候就提供出来,并且在对象的整个生存周期内固定不变。java为什么要把String设计为非可变类呢?你可以问问 james Gosling :)。但是非可变类确实有着自身的优势,如状态单一,对象简单,便于维护。其次,该类对象对象本质上是线程安全的,不要求同步。此外用户可以共享非可变对象,甚至可以共享它们的内部信息。(详见 《Effective java》item 13)。String类在java中被大量运用,甚至在class文件中都有其身影,因此将其设计为简单轻便的非可变类是比较合适的。 一、创建。
好了,知道String是非可变类以后,我们可以进一步了解String的构造方式了。创建一个Stirng对象,主要就有以下两种方式:
java 代码
String str1 = new String("abc"); Stirng str2 = "abc";
虽然两个语句都是返回一个String对象的引用,但是jvm对两者的处理方式是不一样的。对于第一种,jvm会马上在heap中创建一个String对象,然后将该对象的引用返回给用户。对于第二种,jvm首先会在内部维护的strings pool中通过String的 equels 方法查找是对象池中是否存放有该String对象,如果有,则返回已有的String对象给用户,而不会在heap中重新创建一个新的String对象;如果对象池中没有该String对象,jvm则在heap中创建新的String对象,将其引用返回给用户,同时将该引用添加至strings pool中。注意:使用第一种方法创建对象时,jvm是不会主动把该对象放到strings pool里面的,除非程序调用 String的intern方法。看下面的例子:
java 代码
String str1 = new String("abc"); //jvm 在堆上创建一个String对象 //jvm 在strings pool中找不到值为“abc”的字符串,因此 //在堆上创建一个String对象,并将该对象的引用加入至strings pool中 //此时堆上有两个String对象 Stirng str2 = "abc"; if(str1 == str2){ System.out.println("str1 == str2"); }else{ System.out.println("str1 != str2"); } //打印结果是 str1 != str2,因为它们是堆上两个不同的对象 String str3 = "abc"; //此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc” //因此直接返回str2指向的对象给str3,也就是说str2和str3是指向同一个对象的引用 if(str2 == str3){ System.out.println("str2 == str3"); }else{ System.out.println("str2 != str3"); } //打印结果为 str2 == str3
再看下面的例子:
java 代码
String str1 = new String("abc"); //jvm 在堆上创建一个String对象 str1 = str1.intern(); //程序显式将str1放到strings pool中,intern运行过程是这样的:首先查看strings pool //有没“abc”对象的引用,没有,则在堆中新建一个对象,然后将新对象的引用加入至 //strings pool中。执行完该语句后,str1原来指向的String对象已经成为垃圾对象了,随时会 //被GC收集。 //此时,jvm发现strings pool中已有“abc”对象了,因为“abc”equels “abc” //因此直接返回str1指向的对象给str2,也就是说str2和str1引用着同一个对象, //此时,堆上的有效对象只有一个。 Stirng str2 = "abc"; if(str1 == str2){ System.out.println("str1 == str2"); }else{ System.out.println("str1 != str2"); } //打印结果是 str1 == str2
为什么jvm可以这样处理String对象呢?就是因为String的非可变性。既然所引用的对象一旦创建就永不更改,那么多个引用共用一个对象时互不影响。
二、串接(Concatenation)。
java程序员应该都知道滥用String的串接操作符是会影响程序的性能的。性能问题从何而来呢?归根结底就是String类的非可变性。既然 String对象都是非可变的,也就是对象一旦创建了就不能够改变其内在状态了,但是串接操作明显是要增长字符串的,也就是要改变String的内部状态,两者出现了矛盾。怎么办呢?要维护String的非可变性,只好在串接完成后新建一个String 对象来表示新产生的字符串了。也就是说,每一次执行串接操作都会导致新对象的产生,如果串接操作执行很频繁,就会导致大量对象的创建,性能问题也就随之而来了。
为了解决这个问题,jdk为String类提供了一个可变的配套类,StringBuffer。使用StringBuffer对象,由于该类是可变的,串接时仅仅时改变了内部数据结构,而不会创建新的对象,因此性能上有很大的提高。针对单线程,jdk 5.0还提供了StringBuilder类,在单线程环境下,由于不用考虑同步问题,使用该类使性能得到进一步的提高。
三、String的长度
我们可以使用串接操作符得到一个长度更长的字符串,那么,String对象最多能容纳多少字符呢?查看String的源代码我们可以得知类String中是使用域 count 来记录对象字符的数量,而count 的类型为 int,因此,我们可以推测最长的长度为 2^32,也就是4G。
不过,我们在编写源代码的时候,如果使用 Sting str = "aaaa";的形式定义一个字符串,那么双引号里面的ASCII字符最多只能有 65534 个。为什么呢?因为在class文件的规范中, CONSTANT_Utf8_info表中使用一个16位的无符号整数来记录字符串的长度的,最多能表示 65536个字节,而java class 文件是使用一种变体UTF-8格式来存放字符的,null值使用两个字节来表示,因此只剩下 65536- 2 = 65534个字节。也正是变体UTF-8的原因,如果字符串中含有中文等非ASCII字符,那么双引号中字符的数量会更少(一个中文字符占用三个字节)。如果超出这个数量,在编译的时候编译器会报错。
分享到:
相关推荐
C# String 类型:特殊的引用类型 C# String 类型是一个特殊的引用类型,它的实例是只读的。这意味着 String 类型的...最后,需要注意的是,在编程中,我们需要正确地理解 String 类型的特性,以免引发不必要的错误。
【对String的深入理解】 String类在Java编程中扮演着至关重要的角色,它不仅涉及到基本的字符串操作,还涉及到内存管理、性能优化等多个方面。在深入理解String时,我们需要掌握以下几个关键知识点: 1. 引用变量...
在Java编程中,经常需要处理JSON格式的数据,它是一种轻量级的数据交换格式,易于人阅读和编写,同时也易于机器...理解并掌握这些转换方法对于处理JSON数据至关重要,特别是在Java编程中进行Web服务开发或者API交互时。
总的来说,HexString和Base64String的转换是编程中常见的任务,理解它们的工作原理和转换过程对于任何IT从业者来说都是必备技能。掌握这个小程序的使用,不仅可以帮助处理日常开发中的数据编码问题,还能加深对数据...
总的来说,理解`String`对象在编译期和执行期的创建方式对优化Java程序的性能至关重要。编译期的字面量共享可以减少内存占用,而执行期的`new`操作则会导致额外的内存开销。合理选择创建方式,结合使用`...
### List转换成String数组 在Java编程中,我们经常需要对集合进行操作,尤其是在处理大量字符串数据时。本文将详细介绍如何将一个`List<String>`类型的集合转换为`String[]`数组,并通过不同的方法来实现这一过程。...
C#设计者为了提高代码的可读性,推荐在编写代码时使用`string`关键字,因为它更符合英语习惯,易于理解。但是,由于历史原因或者某些特定场景,`String`也会被使用。 `string`类型是不可变的,这意味着一旦创建了一...
本文将深入探讨C#中`String`与`string`之间的区别,帮助开发者更好地理解和使用这两种类型。 #### 1. 基本定义 首先,`string`是C#中的一个关键字,它实际上是`System.String`类型的别名。这意味着`string`并非C#...
### String[] 与 List 相互转化 在 Java 编程语言中,`String[]` 数组和 `List` 集合之间的相互转换是非常常见的需求。...这不仅能提高编程效率,还能帮助开发者更好地理解和运用 Java 集合框架的功能。
在C++编程中,数据类型之间的转换是常见的操作,特别是在处理用户输入或数据存储时。本文将详细讨论如何在...理解并熟练运用这些转换方法是C++编程的基本技能,特别是在处理用户输入、数据持久化或格式化输出等场景。
在实际编程中,理解和熟练运用这些`string`函数是非常必要的。例如,在处理用户输入或文件数据时,我们可能需要使用`strcpy`和`strcat`来组合字符串,使用`strcmp`来比较字符串,使用`strlen`来计算内存需求。同时,...
本文将详细探讨这一转换过程,并通过几个具体的示例来帮助理解。 #### 一、基础知识 在深入讨论如何将列表转换为字符串数组之前,我们首先需要了解一些基本概念。 - **List**:`List`是Java集合框架的一部分,...
首先,要理解STL string的构造函数。例如,当使用以下语句创建string对象时: ```cpp string str1(data); ``` 这里的`str1`会将`data`数组视作C风格字符串,即遇到第一个空字符('\0')时停止复制,因此`str1`只包含...
"String型的不可变性" Java 中的 String 型是一个特殊的包装类数据,它具有不可变性。什么是不可变性呢?...同时,理解 String 对象的创建过程和不可变性对于编写高效和可靠的 Java 程序非常重要。
根据提供的信息,我们可以总结出这份Java基础String类选择题练习题主要聚焦于String及StringBuffer类的使用。尽管具体的题目内容未给出,但从所展示的信息中可以推断出该练习题集涵盖了以下几方面的知识点: ### 一...
这个简单的`string`类介绍将带我们回顾基础,深入理解其内部机制和常用方法。 首先,`std::string`是C++标准库中的一个类模板,它表示可变长度的字符序列。在声明时,你可以通过构造函数初始化字符串,例如: ```...
标题和描述均强调了在Java中处理`String`对象时可能遇到的陷阱,尤其是在理解和使用`String`的处理机制上。文章由天津工业大学软件工程专业的翁龙辉撰写,旨在深入剖析`String`在Java中的独特行为及其潜在的陷阱。...
在Java编程语言中,`String`、`...理解`String`、`StringBuffer`和`StringBuilder`的区别和使用场合,可以帮助开发者写出更高效、更安全的代码。在实际开发中,应根据项目需求和环境选择合适的字符串处理类。
总之,将字符串数组转换为单一的string类型是一项常见的编程任务,理解并掌握不同语言中实现这一操作的方法是提升编程技能的重要一步。无论是C++的`stringstream`,Java的`StringBuilder`,还是C#的`string.Join`,...
`String.xml`文件是Android系统用来存储应用中所有文本资源的主要方式,它使得开发者能够方便地管理和国际化应用的文本内容。本工具就是专为处理`String.xml`与Excel表格之间的相互转换而设计的,方便开发者进行批量...