对于java的学习者而言,无论是初学者,还是java大师,String对于大家而言,也绝对不会陌生。下面本人就从

自己学习的角度大致分析一下String,StringBuffer和StringBuilder这三者的区别和联系。如有不足,欢迎补充说

明~谢谢

    1 String类

String类在java的java.lang.String包下面,需要特别说明的是String类是final关键字修饰的,也就是说String类是不能够被继承的,String中的内容一旦被创建后是不能被修改的。Stirng是对象也不是8种基本数据类型

1) 具体的讲解请看下面的例子:

package com.yonyou.test;

class Test{
public static void main(String[] args) {
String str=new String("龙不吟");
str=new String("虎不啸");//原始String对象中str的内容到底变了没有?
System.out.println(str); //下面也是一个String的例子
String str2="天下太平";
str2=str2+"国泰民安";//原始String对象中的str2到底变了没有?
System.out.println(str2); }
}

    首先说明上述原始String对象中的内容都没有改变!

对于这个问题大家可以这样理解:

如果大家看过String的源码可以发现,String字符串中的内容存储在char数组中的。

在判断原始String对象str和str2的是否改变了,这里需要明白一个问题,在java中相关对象的引用变量一般都存在栈中,而相关的对象都是存在堆中的,栈中的值指向了它所引用的对象(堆中相应的对象的地址)。

     栈 :由JVM分配区域,用于保存线程执行的动作和数据引用。栈是一个运行的单位,Java中一个线程就会相应有一个线程栈与之对应。

一般是用于存储的基本数据类型的局部变量(注意这里仅仅是局部的,对于全局变量不能这样定义哦?)

     堆 :由JVM分配的,用于存储对象等数据的区域。一般用于存储我们new出来的对象。

     常量池 :在堆中分配出来的一块存储区域,用于存储显式 的String,float或者integer.例如String str="abc"; abc这个字符串是显式声明,所以存储在常量池。

对于java内存的更详细的讲解请参考:http://www.cnblogs.com/xiohao/p/4278173.html 这里不再累述。

例如:

创建一个对象String str=new String("Hello World");

对于变量str而言,它代表的是引用变量,它的值是存储在栈中的,而new String("Hello World")会创建一个新的对象,而对象的值是存储在堆中的。而引用

变量str指向对中的对象new String("Hello World"); 这样看来视乎上面的问题就很好解释了。

由于是String修饰的str和str2而言,它们的引用变量的本身是不能够改变,但是它们指向的对象,比如说指向的堆中地址却是可以改变的。

所以说上面String对象str和str2所对应的原始对象都没有改变,仅仅是str和str2所对应的引用变量的指向发生的改变。这段话有一些绕

理解起来不是那么容易,请多读几遍,反复思考一下。

2) 接下来大家可以来理解一下

package com.yonyou.test;

class Test{
public static void main(String[] args) {
String str=new String("Hello World");
String str2="Hello World";
System.out.println("str和str2的equals值相同吗?"+str.equals(str2));
System.out.println("str和str2的==值相同吗?"+(str==str2));//注意此处的str==str2必须用括号括起来,
// 否则的话 字符连接符号 +的优先级高于==,实际上进行的比较是
//str和str2的==值相同吗?Hello World和Hello World是否相同
}
}

  

输出结果为:

str和str2的equals值相同吗?true
 str和str2的==值相同吗?false

这些结果右是怎么输出来的呢?

首先我们需要明白equals和==的区别和联系

对于equals而言,它是 Object类中方法如下:

...

* @param   obj   the reference object with which to compare.
     * @return  <code>true</code> if this object is the same as the obj
     *          argument; <code>false</code> otherwise.
     * @see     #hashCode()
     * @see     java.util.Hashtable
     */

public boolean equals(Object obj) {
 return (this == obj);
    }

通过在这里查看Object类中equals的方法我们知道,如果一个类没有重写Object类中的equals方法的话,那么它的作用和==的作用是一样的。说白了是

没有任何区别的。但是如果用户可以根据自己的需求进行重写equals方法那样的话,equals比较的返回值就和相关的需求相关了。

如在jdk中的String类中的equals方法是这样重写的:

/**
* Compares this string to the specified object. The result is {@code
* true} if and only if the argument is not {@code null} and is a {@code
* String} object that represents the same sequence of characters as this
* object.
*
* @param anObject
* The object to compare this {@code String} against
*
* @return {@code true} if the given object represents a {@code String}
* equivalent to this string, {@code false} otherwise
*
* @see #compareTo(String)
* @see #equalsIgnoreCase(String)
*/
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = count;
if (n == anotherString.count) {
char v1[] = value;
char v2[] = anotherString.value;
int i = offset;
int j = anotherString.offset;
while (n-- != 0) {
if (v1[i++] != v2[j++])
return false;
}
return true;
}
}
return false;
}

  这样我们就可以发现,对于String对象中的equals方法而言,它的目的是比较两个对象所对应的值是否相同,注意仅仅是两个对象的值,跟这两个对象

的引用(地址没有任何关系)。

而对于==而言,它在java中的主要作用则是用来比较java中一些基本类型(如int,long,float等)的值是否相同以及比较两个对象是否有相同(即两个对象的引用

地址是否相同)。

这也就明白了为什么上面的对象equals的值相同而==的值不同。

3)对于下面声明的这个变量创建了几个对象?

String str=new Stirng("xyz"); //创建了几个对象

String str2="abc";//创建了几个对象

首先说“String str=new Stirng("xyz");”创建了一个或者两个

对于“xyz”这个对象而言,它是存放在字符串的缓冲区中的,不管出现多少遍,都是缓冲区中的那一个。而new String()每次都会创建一个新的对象。所以如果之前创建

过“xyz”这个对象的话,那么久创建一个对象,而如果之前要是没有创建过这个字符串的话,那么就会创建两个对象。

其次说String str2=“abc”会创建零个或者一个。

              这个是为什么我就不哆嗦了。

需要注意str和str2是变量名不是对象。

请看下面的这条语句创建了几个对象?

String str="a"+"b"+"c"+"d"+"e"+"f"+"g"+"h"+"i"+"j"+"k";

没错这里仅仅创建了一个对象即str=”abcdefghijk“;

为了更好的说明这个问题我们来看下面的例子:

package com.xiaohao.test;

public class Test{
public static void main(String[] args) {
String str1="ab";
String str2="a"+"b";
String str3="b";
String str4="a"+str3;
System.out.println("str1和str2相等吗?"+(str1==str2));
System.out.println("str1和str4相等吗?"+(str1==str4));
} }

   上面程序的输出结果为:

str1和str2相等吗?true
       str1和str4相等吗?false

这说明javac编译的时候可以对字符串常量直接相加的表达式进行优化,不必等到运行期在进行加法处理,而是在编译的时候直接去掉加号,直接将其编译成这些常量

相连的结果。而对于str4而言由于str3是变量,不是字符串常量,所以最终的结果为false。

下面来讲StringBuffer和StringBuilder

对于StringBuffer和StringBuilder是对Stirng的一个优化。

之前已经说过了,String对象一旦创建后,String中的内容是不能够改变的。每次改变String都会创建新的对象。这样的话会造成相应空间的浪费。介于此jdk额开

发人员计出了StringBuffer和StringBuilder,对于后者而言它们的内容是能够动态改变的。而StringBuffer和StringBuilder的区别就在于StringBuffer是线程安全的

(StringBuffer中的绝大部分方法都加了同步关键字)而StringBuilder是线程不安全的。因为StringBuilder是线程不安全的,所以其运行效率会更高,如果一个字符串

是在方法里面定义的话,这种情况仅仅可能有一个线程访问它,不存在不安全的因素,这时推荐使用StringBuilder。如果一个实例变量是在类里面定义的,并且在多线程

下会访问到,这时最好使用StringBuffer

为了更好的理解StringBuffer和StringBuilder的效率问题,请看下面的例子:

package com.xiaohao.test;

public class Test2 {
public static void main(String[] args) {
String str=new String();
StringBuffer sb1=new StringBuffer();
StringBuilder sb2=new StringBuilder();
long startTime=System.currentTimeMillis();
for(int i=0;i<100000;i++)
{
str=str+i;
}
long endTime=System.currentTimeMillis();
System.out.println("Stirng消耗的时间为:"+(endTime-startTime)); startTime=System.currentTimeMillis();
for(int i=0;i<100000;i++)
{
sb2.append(i);
}
endTime=System.currentTimeMillis();
System.out.println("StirngBuilder消耗的时间为:"+(endTime-startTime)); startTime=System.currentTimeMillis();
for(int i=0;i<100000;i++)
{
sb1.append(i);
}
endTime=System.currentTimeMillis();
System.out.println("StirngBuffer消耗的时间为:"+(endTime-startTime)); }
}

  运行结果为:

Stirng消耗的时间为:42185
    StirngBuilder消耗的时间为:0
    StirngBuffer消耗的时间为:0

相关效率,你懂的~~~

另外StringBuffer和StringBuilder没有重写equals和hashcode方法,它们在存储在java集合框架的时候可能出现问题。

好吧,就先到这里吧。

String,StringBuffer和StringBuilder三者的讲解的更多相关文章

  1. String,StringBuffer和StringBuilder源码解析[基于JDK6]

    最近指导几位新人,学习了一下String,StringBuffer和StringBuilder类,从反馈的结果来看,总体感觉学习的深度不够,没有读出东西.其实,JDK的源码是越读越有味的.下面总结一下 ...

  2. String,StringBuffer和StringBuilder的异同

                                                                    String,StringBuffer和StringBuilder的异同 ...

  3. String,StringBuffer与StringBuilder

    1. String,StringBuffer与StringBuilder的区别 String:存储在常量池中:是不可变的字符序列,任何对String值的改变都会引发新的String对象的生成,因此执行 ...

  4. Java String, StringBuffer和StringBuilder实例

    1- 分层继承2- 可变和不可变的概念3- String3.1- 字符串是一个非常特殊的类3.2- String 字面值 vs. String对象3.3- String的方法3.3.1- length ...

  5. String, StringBuffer and StringBuilder

    一 String 概述: String 被声明为 final,因此它不可被继承. 在 Java 8 中,String 内部使用 char 数组存储数据. public final class Stri ...

  6. String,StringBuffer和StringBuilder

    String,StringBuffer和StringBuilder分别应该在什么情况下使用? String 是Java的字符串类,其实质上也是用Char类型存储的,但是除了hash属性,其他的属性都声 ...

  7. String,StringBuffer,StringBuilder三者有什么异同?

    相同点: 1.三者都是Java平台提供的三种类型得到字符串,它们可以储存和操作字符串. 不同点: 1.String是final修饰的,也就意味着String引用的字符串内容是不能被改变的.而Strin ...

  8. String,StringBuffer,StringBuilder三者的区别

    相同点: String,StringBuffer,StringBuilder,都是final类,不允许被继承,在本质上都是字符数组, 不同点: 1.String的长度是不可变的而后两者长度可变,在进行 ...

  9. String StringBuffer和StringBuilder区别及性能

    结论: (1)如果要操作少量的数据用 String: (2)多线程操作字符串缓冲区下操作大量数据 StringBuffer: (3)单线程操作字符串缓冲区下操作大量数据 StringBuilder(推 ...

随机推荐

  1. kubernetes 与LVM的结合

    本文主要介绍k8s与LVM结合使用的场景,在原生的k8s中对于本地存储提供了hostPath与emptyDir两种volme,hostPath是直接将文件存储在本地主机上,存在的问题是无法进行quot ...

  2. masm32环境配置

    软件: Windows7-32bit visual c++6.0 Masm32 sdk 11 安装: 0x00 || 下载Masm sdk 11并安装,下载路径:http://www.masm32.c ...

  3. 五一,期待一场这样的旅行,提前预祝Csdner五一快乐

    五一,期待一场这样的旅行,提前预祝Csdner五一快乐 五一,你是否期待一次这样的旅行: 住在一间安静优美的小屋,在鸟鸣中起床,推窗有花香铺面而来.早餐过后,在阳光温暖的抚摸里,骑车踏青或光脚奔跑. ...

  4. (转)OpenStack之服务端口号

    原文:https://blog.csdn.net/henulwj/article/details/47276391 在部署openstack的过程中,你会遇到配置各种服务的endpoint,opens ...

  5. (转)MySQL高可用解决方案

    MySQL高可用解决方案 原文:http://www.ywnds.com/?p=5565 有这么两个概念,数据库的可靠性和数据库的可用性,可靠性指的是数据可靠,而可用性指的是服务可用.但是不管是可靠性 ...

  6. CentO7 安装 redis, 主从配置,Sentinel集群故障转移切换

        一.Redis的安装(前提是已经安装了EPEL)   安装redis: yum -y install redis 启动/停止/重启 Redis 启动服务: systemctl start re ...

  7. Flex4 outerDocument

    <?xml version="1.0" encoding="utf-8"?> <s:Application xmlns:fx="ht ...

  8. Java将Excel的列数以字母表示的字符串转换成数字表示

    我们知道,在 Excel 中,行数用数字表示,而列数是用字母表示的(如下图所示),有时候需要把它转换成数字来使用,或者把数字转换成字母.(例如使用POI操作Excel) 下面是转换代码,用来进行字母和 ...

  9. 如何在 Azure 中创建 ASP.NET Web 应用

    Azure Web 应用提供高度可缩放.自修补的 Web 托管服务. 本快速入门演示如何将第一个 ASP.NET Web 应用部署到 Azure Web 应用中. 完成后,便拥有了一个资源组,该资源组 ...

  10. JAVA基础之——序列化和反序列化

    1 概念 序列化,将java对象转换成字节序列的过程. 反序列化,将字节序列恢复成java对象的过程. 2 为什么要序列化? 2.1 实现数据持久化,当对象创建后,它就会一直在,但是在程序终止时,这个 ...