从String类型字符串的比较到StringBuffer和StringBuilder

1. String类型

  • String类源码

  为了从本质上理解String类型的特性所在,我们从String类型的源码看起,在源码中String类的注释中存在以下:

/**Strings are constant; their values cannot be changed after they
 * are created. String buffers support mutable strings.
 * Because String objects are immutable they can be shared. For example:
 * String str = "abc";
 * is equivalent to:
 *     char data[] = {‘a‘, ‘b‘, ‘c‘};
 *     String str = new String(data); */

  从中可以理解到:首先,字符串是常量(constant),创建之后就不能再改变;其次,因为String对象时不可变(immutable)量,因此他们是不能共享的,即说明是线程安全的。之后又指出,一个字符串对象相当于一个字符数组。

  继续看下去,发现String类使用final关键字修饰,说明String类不能被继承的。继续看类的成员变量: 

/** The value is used for character storage. */
    private final char value[];

  用来存储字符的数组类型也使用final修饰,进一步说明String类型的实例在创建完之后是不可变的。

  调用任何String类中的方法不会修改String自身值,除非重新生成对象。

  • equals()和“==”

  equals()方法定义在Object类中,比较的是两个对象的内容;而使用“==”比较的是两个对象的地址,或者说是引用。

  Object类的源码中对equals()方法的定义也是采用“==”的方法来比较:

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

  这说明如果继承自Obejct类的equals()方法如果不经重写,仍然是采用比较对象的方式,从而必须在有需要的时候重写equals()方法进行自定义方式的比较。

  String类中即对equals()方法进行了重写:

public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }

  如果两者均为同一对象的引用,则说明相等;如果两个均为String类实例,则需要比较String字符数组,具体为比较字符数组的长度并遍历其中的内容与比较。

  • 常量池和String类

常量池在java用于保存在编译期已确定的,已编译的class文件中的一份数据。它包括了关于类,方法,接口等中的常量,也包括字符串常量,如String s = "java"这种字面值的声明方式;当然也可扩充,执行器产生的常量也会放入常量池,即常量池具有动态性,运行期间可以将新的常量加入常量池中,故认为常量池是JVM的一块特殊的内存空间。

虚拟机为每个被装载的类型维护一个常量池,池中为该类型所用常量的一个有序集合,包括直接常量(String、Integer和float常量)和对其他类型、字段和方法的符号引用

  池化思想:把需要共享的数据放在池中,用一个存储区域俩存放一些公共的资源以减少和控制存储空间的开销。

  在定义String时,如果采用字面值方式进行创建:

String str1 = "myString";
String str2 = "myString";

  编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”,创建字符串对象;如果存在的话,则不用在常量池中重新开辟空间。反而需要在栈中开辟一块空间,命名为“str2”,存放的值为常量池中“myString”的内存地址,即返回串池中的字符串的地址,并将该地址赋给对象变量。

  在定义String时,如果采用new方式进行创建:

String str = new String("myString");

  在程序编译期,编译程序先去字符串常量池检查,是否存在“myString”,如果不存在,则在常量池中开辟一个内存空间存放“myString”;如果存在的话,则不用重新开辟空间,保证常量池中只有一个“myString”常量,节省内存空间。然后在内存堆中开辟一块空间存放new出来的String实例,在栈中开辟一块空间,命名为“str”,存放的值为堆中String实例的内存地址,这个过程就是将引用str指向new出来的String实例。堆中存放new出来的对象,栈中存放指向对象的指针。


2. StringBuffer和StringBuilder

  利用StringBuilder和StringBuffer拼接字符串而不是String

  StringBuffer和StringBuilder都继承了抽象类AbstractStringBuilder,这个抽象类和String一样也定义了char[] value和int count,但是与String类不同的是,它们没有final修饰符。因此得出结论:String、StringBuffer和StringBuilder在本质上都是字符数组,不同的是,在进行连接操作时,String每次返回一个新的String实例,而StringBuffer和StringBuilder的append方法直接返回this,所以这就是为什么在进行大量字符串连接运算时,不推荐使用String,而推荐StringBuffer和StringBuilder。

  在String类中,因为属性值不可变吗,当连接字符串的时候也就只能不断创建新的对象,对于有许多字符串连接时,应该使用StringBuffer类或者StringBuilder类,使用其实例化对象来进行字符串的连接时就不会有多余的中间对象生成。

  例如:对于字符串连接String str = "A" +  "B" + "C" +  "D" ;产生有“AB”,“ABC”,“ABCD”,造成常量池中明显产生了多余的对象,浪费了空间。

    StringBuffer stringBuffer = new StringBuffer("A");
    stringBuffer.append("B");
    stringBuffer.append("C");
    stringBuffer.append("D");
    System.out.println(stringBuffer.toString());

  StringBuffer和StringBuilder类的区别:

  StringBuffer在方法前加了一个synchronized修饰,起到同步的作用,可以在多线程环境使用,为此付出的代价就是降低了执行效率。因此,如果在多线程环境可以使用StringBuffer进行字符串连接操作,单线程环境使用StringBuilder,它的效率更高。



从String类型字符串的比较到StringBuffer和StringBuilder

时间: 2024-10-27 12:50:39

从String类型字符串的比较到StringBuffer和StringBuilder的相关文章

删除string类型字符串中指定字符串段

1.实现背景 在插入list行时用邮件的MessageID给对应行命名. 在回复全部邮件时,收件人变为之前收件人中出去“自己”同时加入之前发件人,抄送人还是之前的抄送人,密送人不用管,直接不用带. 在“回复全部”按钮响应函数里面 CListUI* pList = static_cast<CListUI*>(m_PaintManager.FindControl(_T("middle_comlumn_header1")));//拿到list控件指针            int

在java中,将String类型字符串s赋值为null后,将字符串与其他字符串拼接后得到结果出现了null字符串与其他字符连接的样式

String s = null; s  += "hello"; System.out.println(s); 结果为:nullhello 原因: 先应用String.valueOf 得出s的value值,再通过StringBuilder拼接hello,因此将value与hello进行了拼接: String s = null; s = (new StringBuilder(String.valueOf(s))).append("hello").toString();

String【字符串】

属性 public final class String 字符串在java中是一个类,然后这个类是一个太监类 类面里面肯定有属性 private final char value[]; final 这个变量value的引用只能被初始化一次,而且引用没法进行修改 但是数组中的值还是可以被改变的 private 就保证这个char类型数组只能被当前类所使用 而且string类中没有提供设置数组的方法,禁止外部的修改 对于我们的字符串来讲,如果我们对字符串做了拼接,删除的操作,会重新创建新的字符串 内

java中String和StringBuffer以及StringBuilder的区别

我个人觉得理解String和StringBuffer以及StringBuilder的区别比较重要.在讨论他们的区别时,我们首先应该知道java中的String. 首先讨论String. 翻看String.java源码,会知道string的一个重要秘密: 在string中,其实内部是通过一个char数组来维护这个string的,并且还定义了一个记录该string在这个数组的起始位置的索引,以及定义了这个string的长度.  重点是他们都是final类型. private final char[]

C#:string、stringBuffer、stringBuilder的区别

好脑子不如烂笔头,总是记不住,记下来吧 依然 搬运 地址: http://blog.csdn.net/qq_28187979/article/details/76607253 ----------------------------------------------------------------------------------------------------------------------- 最近对这几个傻傻分不清楚,在网上搜集了一些资料,现在总结一下. string是基本类

String、StringBuffer和StringBuilder源码解析

1.String 1.1类的定义 public final class String implements java.io.Serializable, Comparable<String>, CharSequence String类在定义时候使用final关键字进行修饰,限制了这个类无法被继承,里面的方法也无法被重写. 同时它还实现了Serializable接口.Comparable接口,以及CharSequence接口三个接口: Serializable:序列化接口,如果允许对象被序列化需要

C++中关于string类型究竟能不能用cout输出的问题

先让我讲下故事哈 一次在MFC中用cout输出一个string类型字符串,编译时出现这样一个错误: error C2679: binary '<<' : no operator defined which takes a right-hand operand of type 'class std::basic_string<char,struct std::char_traits<char>,class std::allocator<char> >' (or

【Java面向对象基础(二)】细说String、StringBuffer和StringBuilder

[喵"的Android之路][基础篇(二)][Java面向对象基础]细说String.StringBuffer和StringBuilder 1.String String是Java中的一个final类,主要用于字符串的处理. 1.1 不可变性 String内的字符串是不可变的,每一次修改都会重新生成一个新的String对象实例. 例: 1 // 在堆中会创建一个"Hello"字符串实例,把地址赋给对象a 2 String a = new String("Hello&

Java中的String,StringBuffer,StringBuilder详解与区别

1.String Java中string类是不可变的,其中在声明的源代码中用的final,所以只能声明一次.所以每次在明面上的改变其实是重新生成一个String对象,指针指向新的String对象.同时,String内部重写的了equal的方法,原本Object的equal就是两个对象相等就可以,但是现在,并不能靠对象相等来判断值相等了,重写的equal中会挨个比较字符,这也就是为啥比较同样内容字符串要用equal的原因. 同时String a="111"+"222"