`
落地窗
  • 浏览: 438245 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

String,StringBuffer,StringBuilder和常量池

阅读更多
String是固定长度的字符串,如果要发生变化必须重新生成新的实例;
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
简要的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。而在某些特别情况下, String 对象的字符串拼接其实是被 JVM 解释成了 StringBuffer 对象的拼接,所以这些时候 String 对象的速度并不会比 StringBuffer 对象慢,而特别是以下的字符串对象生成中, String 效率是远要比StringBuffer 快的:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuilder(“This is only a”).append(“ simple”).append(“ test”);
你会很惊讶的发现,生成 String S1 对象的速度简直太快了,而这个时候 StringBuffer 居然速度上根本一点都不占优势。其实这是 JVM 的一个把戏,在 JVM 眼里,这个
String S1 = “This is only a” + “ simple” + “test”; 其实就是:
String S1 = “This is only a simple test”; 所以当然不需要太多的时间了。但大家这里要注意的是,如果你的字符串是来自另外的 String 对象的话,速度就没那么快了,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
这时候 JVM 会规规矩矩的按照原来的方式去做,在大部分情况下 StringBuffer > String
StringBuffer
Java.lang.StringBuffer线程安全的可变字符序列。一个类似于 String 的字符串缓冲区,但不能修改。虽然在任意时间点上它都包含某种特定的字符序列,但通过某些方法调用可以改变该序列的长度和内容。
可将字符串缓冲区安全地用于多个线程。可以在必要时对这些方法进行同步,因此任意特定实例上的所有操作就好像是以串行顺序发生的,该顺序与所涉及的每个线程进行的方法调用顺序一致。
StringBuffer 上的主要操作是 append 和 insert 方法,可重载这些方法,以接受任意类型的数据。每个方法都能有效地将给定的数据转换成字符串,然后将该字符串的字符追加或插入到字符串缓冲区中。append 方法始终将这些字符添加到缓冲区的末端;而 insert 方法则在指定的点添加字符。
例如,如果 z 引用一个当前内容是“start”的字符串缓冲区对象,则此方法调用 z.append("le") 会使字符串缓冲区包含“startle”,而 z.insert(4, "le") 将更改字符串缓冲区,使之包含“starlet”。
java.lang.StringBuilder一个可变的字符序列是5.0新增的。此类提供一个与 StringBuffer 兼容的 API,但不保证同步。该类被设计用作 StringBuffer 的一个简易替换,用在字符串缓冲区被单个线程使用的时候(这种情况很普遍)。如果可能,建议优先采用该类,因为在大多数实现中,它比StringBuffer 要快。两者的方法基本相同。
与C/C++语言不同的是java中并没有把字符串作为一种基本的数据类型,而是在java.lang包中提供了处理字符串的类String,该类用于处理“不可变”的字符串;与之对应的还有,StringBuffer类用于处理“可变的”字符串。

注意:这两种类都被声明为final型,因此不可以被当做父类继承使用。

一、String类

由类String所创建的对象在创建之后是不可以更改的,被视为常量。

举例说明:

subString是String类中重要的处理字符串的方法

String str = "Hello world!";

Str = str.subString(6);

在上述语句中,str.subString(6);重新创建了一个字符串String对象,然后把这个对象赋值给str。





二、StringBuffer类

StringBuffer类是字符串缓冲区存储类,创建是可以更改长度的字符串对象,该字符串被视为常量,可以调用类方法改变字符串的长度和内容。

实现机理:创建对象时开辟一个缓冲区存放字符串序列,可以向字符串追加、插入操等作。在超过缓存区的容量时,java会自动扩大缓冲区的容量,保证操作的安全性。





三、StringBuilder类

StringBuilder类使用方法和StringBuffer类类似。

区别:StringBuffer类适用于多线程方法,StringBuilder类适用于单线程操作。StringBuilder对象的执行效率比StringBuffer对象要高。

StringBuilder是J2SE   5.0才新增的类,在J2SE   5.0之前的版本若有相同的需求,则使用java.lang.StringBuffer。事实上,StringBuilder被设计为与StringBuffer具有相同的操作接口。在单机非多线程(Multithread)的情况下使用StringBuilder会有较好的效率,因为StringBuilder没有处理同步(Synchronized)问题。StringBuffer则会处理同步问题,如果StringBuilder会在多线程下被操作,则要改用StringBuffer,让对象自行管理同步问题。

======================================================================
string是java中的字符串。String类是不可变的,对String类的任何改变,都是返回一个新的String类对象。下面介绍java中的String与常量池。


1. 首先String不属于8种基本数据类型,String是一个对象。

因为对象的默认值是null,所以String的默认值也是null;但它又是一种特殊的对象,有其它对象没有的一些特性。


2. new String()和new String(“”)都是申明一个新的空字符串,是空串不是null;


3. String str=”kvill”;String str=new String (“kvill”);的区别:

在这里,我们不谈堆,也不谈栈,只先简单引入常量池这个简单的概念。

常量池(constant pool)指的是在编译期被确定,并被保存在已编译的.class文件中的一些数据。它包括了关于类、方法、接口等中的常量,也包括字符串常量。

看例1:

String s0=”kvill”;  
String s1=”kvill”;  
String s2=”kv” + “ill”;  
System.out.println( s0==s1 );  
System.out.println( s0==s2 );  

结果为:

true   
true  

首先,我们要知道Java会确保一个字符串常量只有一个拷贝。

因为例子中的s0和s1中的”kvill”都是字符串常量,它们在编译期就被确定了,所以s0==s1为true;而”kv”和”ill”也都是字符串常量,当一个字符串由多个字符串常量连接而成时,它自己肯定也是字符串常量,所以s2也同样在编译期就被解析为一个字符串常量,所以s2也是常量池中”kvill”的一个引用。

所以我们得出s0==s1==s2;

用new String() 创建的字符串不是常量,不能在编译期就确定,所以new String() 创建的字符串不放入常量池中,它们有自己的地址空间。

看例2:
String s0=”kvill”;  
String s1=new String(”kvill”);  
String s2=”kv” + new String(“ill”);  
System.out.println( s0==s1 );  
System.out.println( s0==s2 );  
System.out.println( s1==s2 );  

结果为:

false  
false  
false  

例2中s0还是常量池中”kvill”的应用,s1因为无法在编译期确定,所以是运行时创建的新对象”kvill”的引用,s2因为有后半部分new String(“ill”)所以也无法在编译期确定,所以也是一个新创建对象”kvill”的应用;明白了这些也就知道为何得出此结果了。

4. String.intern():


再补充介绍一点:存在于.class文件中的常量池,在运行期被JVM装载,并且可以扩充。String的intern()方法就是扩充常量池的一个方法;当一个String实例str调用intern()方法时,Java查找常量池中是否有相同Unicode的字符串常量,如果有,则返回其的引用,如果没有,则在常量池中增加一个Unicode等于str的字符串并返回它的引用;看例3就清楚了

例3:

String s0= “kvill”;  
String s1=new String(”kvill”);  
String s2=new String(“kvill”);  
System.out.println( s0==s1 );  
System.out.println( “**********” );  
s1.intern();  
s2=s2.intern(); //把常量池中“kvill”的引用赋给s2  
System.out.println( s0==s1);  
System.out.println( s0==s1.intern() );  
System.out.println( s0==s2 );  

结果为:

false  
**********  
false //虽然执行了s1.intern(),但它的返回值没有赋给s1  
true //说明s1.intern()返回的是常量池中”kvill”的引用  
true 

最后我再破除一个错误的理解:

有人说,“使用String.intern()方法则可以将一个String类的保存到一个全局String表中,如果具有相同值的Unicode字符串已经在这个表中,那么该方法返回表中已有字符串的地址,如果在表中没有相同值的字符串,则将自己的地址注册到表中“如果我把他说的这个全局的String表理解为常量池的话,他的最后一句话,“如果在表中没有相同值的字符串,则将自己的地址注册到表中”是错的:

看例4:

String s1=new String("kvill");  
String s2=s1.intern();  
System.out.println( s1==s1.intern() );  
System.out.println( s1+" "+s2 );  
System.out.println( s2==s1.intern() );  

结果:

false 
kvill kvill  
true  

在这个类中我们没有声名一个”kvill”常量,所以常量池中一开始是没有”kvill”的,当我们调用s1.intern()后就在常量池中新添加了一个”kvill”常量,原来的不在常量池中的”kvill”仍然存在,也就不是“将自己的地址注册到常量池中”了。

s1==s1.intern()为false说明原来的“kvill”仍然存在;

s2现在为常量池中“kvill”的地址,所以有s2==s1.intern()为true。


5. 关于equals()和==:

这个对于String简单来说就是比较两字符串的Unicode序列是否相当,如果相等返回true;而==是比较两字符串的地址是否相同,也就是是否是同一个字符串的引用。


6. 关于String是不可变的

这一说又要说很多,大家只要知道String的实例一旦生成就不会再改变了,比如说:String str=”kv”+”ill”+” “+”ans”;
就是有4个字符串常量,首先”kv”和”ill”生成了”kvill”存在内存中,然后”kvill”又和” “ 生成 ”kvill “存在内存中,最后又和生成了”kvill ans”;并把这个字符串的地址赋给了str,就是因为String的“不可变”产生了很多临时变量,这也就是为什么建议用StringBuffer的原因了,因为StringBuffer是可改变的。
分享到:
评论

相关推荐

    String-StringBuffer-StringBuilder

    这是因为`String`对象存储在常量池中,每次对`String`对象的操作都会创建一个新的`String`对象,而不是修改原来的对象。这种设计使得`String`对象非常适用于作为键(key)在哈希表(如`HashMap`)中使用,因为不变性...

    String&StringBuffer&StringBuilder三者之间的区别-经典解析.doc

    在Java编程语言中,String、StringBuffer和StringBuilder都是用来处理字符串的重要类,它们各自有特定的使用场景和特性。理解这三个类的区别对于任何Java开发者,无论是初学者还是经验丰富的程序员,都是非常重要的...

    String和StringBuilder、StringBuffer的区别1

    在Java编程语言中,`String`、`StringBuilder`和`StringBuffer`是处理字符串的三种主要类型,它们各自具有不同的特性和使用场景。下面将详细解释它们之间的主要区别。 首先,`String`类是最基本的字符串类型,它...

    String与StringBuffer区别详解

    这是因为`String`对象存在于常量池中,修改操作实际上是在常量池中创建新的引用,而不是修改原有的对象。 - `StringBuffer`(或`StringBuilder`)则提供了可变性,可以在已有内容的基础上进行修改,而无需每次都...

    String、StringBuilder和StringBuffer超详解

    在Java编程语言中,`String`、`StringBuilder`和`StringBuffer`都是处理字符串的重要类,但它们在处理方式和性能上有显著的区别。下面将详细解释这三个类的特点和使用场景。 1. **String类** - `String`类是final...

    String总概况及其特性并与StringBuffer的区别详解

    - **节省内存**:当多个变量引用相同的字符串字面量时,Java只会在常量池中存储一份副本,从而避免了内存浪费。 - **哈希码一致性**:`String`的不可变性确保了其哈希码在对象生命周期内保持不变,这对于散列表如`...

    Java-String&StringBuilder&StringBuffer的区别与分析

    Java中的String、StringBuilder和StringBuffer类都是用于处理字符串的,但在不同的...对于String的不可变性,可以利用其特性来实现字符串常量池,优化内存使用。了解这些差异,有助于写出更加高效和安全的Java代码。

    什么是字符串常量池?Java开发Java经验技巧共6页.p

    在Java编程语言中,字符串常量池(String Constant Pool)是一个重要的概念,它与程序的内存管理和性能优化密切相关。理解这个概念对于任何Java开发者来说都至关重要。字符串常量池是Java虚拟机(JVM)在运行时为...

    String和StringBuffer深入.doc

    这是因为`String`对象在Java中存储在常量池中,每次对`String`对象进行修改时,实际上都会创建一个新的`String`对象,而不是改变原来的对象。这种特性使得`String`对象适合用作不可变数据,比如作为方法参数或返回值...

    stringbuffer和string的区别.pdf

    在实际开发中,我们需要根据实际场景合理选择使用String、StringBuffer或StringBuilder,以达到最好的性能和效率。例如,在非频繁修改的场景下,使用String更简单方便;而在需要频繁修改字符串的场景下,使用...

    字符数组的存储方式 字符串常量池.docx

    在Java编程语言中,字符串是极其重要的数据类型,它们...总之,理解字符串常量池和字符串在JVM中的存储方式对于优化代码性能至关重要。正确地使用字符串和理解其内存管理机制可以避免不必要的内存开销,提升程序效率。

    5讲String、StringBuffer、Stri...1

    2. JVM对象缓存:了解`String`池的概念,以及何时和为什么字符串常量会被存储在池中。 3. 优化技巧:如何通过预估字符串长度来减少`StringBuffer`或`StringBuilder`的扩容次数,从而提高性能。 4. 类的演进:例如,...

    java基础知识面试题

    本文将围绕 Java 基础知识面试题展开,涵盖 String、StringBuffer、StringBuilder 的区别、==和 equals 的区别、String 常量池等知识点。 一、String、StringBuffer、StringBuilder 的区别 String、StringBuffer、...

    10个有关String的面试问题Java开发Java经验技

    3. **String、StringBuffer和StringBuilder的区别是什么?** String是不可变的,适合不需修改的情况。而StringBuffer和StringBuilder都是可变的,它们提供线程安全(StringBuffer)和非线程安全(StringBuilder)的...

    【Java基础笔记】String类以及StringBuffer Builder.docx

    本文主要关注Java中的三个字符串相关类:`String`、`StringBuilder`和`StringBuffer`。理解它们的特性和使用方法对于编写高效、线程安全的代码至关重要。 一、`String`类 `String`类在Java中是一个不可变类,意味着...

    String创建对象

    这种方式创建的`String`对象会存储在常量池中,因为它们是编译时常量。 2. **构造函数创建**: `String`类提供了多个构造函数,允许我们通过字符数组或另一个`String`对象来创建新对象。例如: ```java char[] ...

    Java资深开发工程师知识体系.docx

    String、StringBuilder、StringBuffer 都是 Java 中的字符串类,但是它们有不同的设计目标和使用场景: * String 类是不可变的,适合读取操作。 * StringBuilder 类是可变的,适合大量字符串拼接操作。 * ...

    详解Java的String类型程序

    由于`a`和`b`都指向字符串常量池中的同一份`"hehe"`实例,所以它们的地址相同。 - `if (a == c)`: 结果为假。因为`c`是在堆上创建的对象,与`a`指向的字符串常量池中的实例地址不同。 - `if (a.equals(c))`: 结果...

    java 中string 和srtingbuffer的区别

    - `String`的内存占用:`String`对象的值是常量,一旦创建就会在内存的常量池中存储,修改`String`对象实际上是在常量池中创建新的对象。如果程序中有很多未被引用的旧`String`对象,它们不会立即被垃圾回收,可能...

    正确使用String类的几点注意

    这种方式创建的String对象位于常量池中,具有不可变性(immutable),即一旦创建后其内容就不能改变。 **1.2 使用new关键字** 另一种常见的初始化方法是使用`new`关键字: ```java String s = new String("hello")...

Global site tag (gtag.js) - Google Analytics