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类中,比较的是两个对象的内容;而使用“==”比较的是两个对象的地址,或者说是引用。

  equals()方法不适用基本类型的比较,基本类型的比较直接使用相应运算符;

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

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

  这说明如果继承自Obejct类的equals()方法如果不经重写,仍然是采用比较对象的方式,从而必须在有需要的时候重写equals()方法进行自定义方式的比较,即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的更多相关文章

  1. 判断String类型字符串是否为空的方法

    在项目中经常遇到要判断String类型的字段是否为空操作 我们可以用Apache提供的StringUtils这个工具类,不用自己去判断,也不用自己封装判断空的方法 它有两个版本,一个是org.apac ...

  2. 6.2 C++ string类型字符串的连接

    参考:http://www.weixueyuan.net/view/6391.html 总结: 对于string类型变量,我们可以直接用“+”或者“+=”进行字符串的连接,操作符非常方便. 用“+”风 ...

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

    1.实现背景 在插入list行时用邮件的MessageID给对应行命名. 在回复全部邮件时,收件人变为之前收件人中出去“自己”同时加入之前发件人,抄送人还是之前的抄送人,密送人不用管,直接不用带. 在 ...

  4. 解决springmvc使用@ResponseBody返回String类型字符串中文乱码问题

    问题分析: 首先: 确定的是只有当返回值是 String时才会出现中文乱码,而当返回值是Map<String, Object>或者是其它类型时,并没有中文乱码的出现. 然后找原因: 原因是 ...

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

    String s = null; s  += "hello"; System.out.println(s); 结果为:nullhello 原因: 先应用String.valueOf ...

  6. Json格式String类型字符串转为Map工具类

    package agriculture_implement.util; import com.google.gson.Gson; import com.google.gson.JsonSyntaxEx ...

  7. 从源代码的角度聊聊java中StringBuffer、StringBuilder、String中的字符串拼接

    长久以来,我们被教导字符串的连接最好用StringBuffer.StringBuilder,但是我们却不知道这两者之间的区别.跟字符串相关的一些方法中总是有CharSequence.StringBuf ...

  8. String、StringBuffer、StringBuilder源码解读

    序 好长时间没有认真写博客了,过去的一年挺忙的.负责过数据库.线上运维环境.写代码.Code review等等东西挺多. 学习了不少多方面的东西,不过还是需要回归实际.加强内功,方能扛鼎. 去年学习M ...

  9. [ Java学习基础 ] String、StringBuffer、StringBuilder比较学习

    首先讲获得字符串对象的方式有两种,一种是直接使用字符串常量,一种是使用new关键字创建,但它们之间是有一些区别,如下运行实例: String s1 = new String("Hello&q ...

随机推荐

  1. OC中的copy

    copy的概念 Copy的字面意思是"复制"."拷贝",是一个产生副本的过程 对象拷贝的目的:要使用某个对象的数据,但是在修改对象的时候不影响原来的对象内容,常 ...

  2. MapControl Application 添加自定义的工具条

    现在想用二次开发做一些东西,然后需要自定义的工具条,但是如何向MapControl Application 添加自定义的工具条呢,经过多次试验后,终于找到了相应的方法(左图是添加自定义的工具条之前,右 ...

  3. C#集合之并发集合

    .NET 4 开始,在System.Collection.Concurrent中提供了几个线程安全的集合类.线程安全的集合可防止多个线程以相互冲突的方式访问集合. 为了对集合进行线程安全的访问,定义了 ...

  4. 2017最新最稳定的彩票源码PHP+mysql 新增彩种+全新界面

    网站后台管理系统:新闻资讯系统 用户管理系统用户登录日志彩种规则说明玩法时间设置彩票期号管理足球对阵管理彩票方案撤单彩票出票管理开奖号码管理彩票方案查询彩票中奖查询 彩票追号查询服务支持中心财务中心管 ...

  5. Oracle 12C 新特性之表分区或子分区的在线迁移

    Oracle 12c 中迁移表分区或子分区到不同的表空间不再需要复杂的过程.与之前版本中未分区表进行在线迁移类似,表分区或子分区可以在线或是离线迁移至一个不同的表空间.当指定了 ONLINE 语句,所 ...

  6. XSS攻击及预防

    跨站脚本攻击(Cross Site Scripting),为不和层叠样式表(Cascading Style Sheets, CSS)的缩写混淆,故将跨站脚本攻击缩写为XSS.恶意攻击者往Web页面里插 ...

  7. 【转】MyISAM和InnoDB 区别

    InnoDB和MyISAM是MySQL最常用的两个表类型,这两个表类型各有优劣,视具体应用而定.基本的差别为:MyISAM类型不支持事务处理等高级处理,而InnoDB类型支持.MyISAM类型的表强调 ...

  8. 【原创】iOS图片预览(支持缩放和移动)

    1.传入图片 PreViewController.h: #import <UIKit/UIKit.h> @interface PreViewController : UIViewContr ...

  9. openfire源码解读--用户登录

    根据xmpp协议 客户端发送: <auth xmlns='urn:ietf:params:xml:ns:xmpp-sasl' mechanism='PLAIN'>XXXXXXXXXXXXX ...

  10. 获取openId | 小程序

    最近项目中需要使用微信授权,继上一篇<关于微信小程序拒绝授权后,重新授权并获取用户信息>之后,需要获取用户的openId,开发测试时,发现无论如何都获取不到: 官方文档如下: 相信很多同学 ...